trigger all releases from master (#6016)

trigger all releases from master

The 1.1.0 release went wrong and we had to trash it and release 1.1.1
instead. This is an attempt at identifying and correcting the root
cause behind that incident.

To understand the situation, we need to know how releases worked before
1.0. We had a one-line file called `LATEST` that specifies the git SHA and
version tag for the latest release. A change to that file triggered a
release with the specified release tag, built from the source tree of
the specified commit. The `LATEST` file looked something like:

```
f050da78c9 1.0.0-snapshot.20200411.3905.0.f050da78
```

To mark a release as stable, we would change it to look like this:

```
f050da78c9 1.0.0
```

i.e. simply drop the `-snapshot...` suffix. Even though the commit (and
thus the entire source tree we build from) is the same, we would need to
rebuild almost all of our release artifacts, as they embed the version
tag in various places and ways. That worked well as long as we could
assume we were doing trunk-based development, i.e. all releases would
always come from the same (`master`) branch.

When we released 1.0, and started work on 1.1, we had a few bug reports
for 1.0 that we decided should be resolved in a point release. We
decided that the best way to handle that would be to have a branch
starting on the release commit for 1.0, and then backport patches from
`master` to that branch. We adapted our build process to also watch the
`release/1.0.x` branch and, in particular, trigger a new release build if
the `LATEST` file in that branch changed. That worked well.

The plan going forward was to keep doing regular snapshot releases from
the `master` branch, and create support, point releases ("patch" releases
in semver) from dedicated branches.

On April 30, we made a snapshot release as an RC for 1.1.0, by changing
the `LATEST` file in the `master` branch. That release was built on commit
681c862d. On May 6, we decided to take a new snapshot as the RC for
1.1.0; we changed `LATEST` in `master` to designate 7e448d81 as the new
latest release.

On May 11, we noticed an issue that broke our builds. Without going into
details, an external artifact we depend on had changed in incompatible
ways. After fixing that on `master`, we reasoned that this would also
break the build of the final 1.1.0 release if we just tried to build
7e448d81 again. But as the target release date was May 13, we did not
want to take a new snapshot after that fix, as that would have included
one more week of work in the release, and given us no time to test it.

So we did what we did for the 1.0 branch, as it had worked well: we
created a branch that forked from `master` at commit 7e448d81 and called
it `release/1.1.x`, then cherry-picked the one fix to our build process to
work around the broken download. When the time came to make the final
1.1.0 build on May 13, we naturally picked the `LATEST` file from the
`release/1.1.x` branch and dropped the `-snapshot...` suffix. Importantly,
we did not need to update the target commit to include the "broken
download" fix as, in the meantime, the internet had fixed itself, and we
thus reasoned we should go for the exact code of the RC rather than
include an unnecessary, albeit seemingly harmless, change.

Everything went well with the release process. Tests went well too. Then
we got a report that an application that worked against the latest RC
broke with the final 1.1.0. The issue was that we had built the wrong
commit: by branching off at the point of the _target_ commit for the
latest snapshot, we did not have the change to the `LATEST` file that
designated that commit as the target. So the `LATEST` file in
`release/1.1.x` was still pointing to 681c862d.

I believe the root cause for this issue is the fact that we have
scattered our release process over multiple branches, meaning there is
no linear history of what was released and we are relying on people
being able to mentally manage multiple timelines. Therefore, I propose
to fix our release process so this should not happen again by
linearizing the release process, i.e. getting back to a situation where
all releases are made from a single branch, `master`.

Because we do want to be able to release _for_ multiple release branches
(to provide backports and bugfixes), we still need some way to
accommodate that. Having a single `LATEST` file in the same format as
before would not really work well: keeping track of interleaved release
streams on a single file would not really be easier than keeping track
of multiple branches.

My proposed solution is to instead have a multiline LATEST file, so that
all the release branch "tips" can be observed at the same time, and, as
long as we take care to only advance one release branch at a time, we
can easily keep track of each of them. This is what this PR does.

This required a few changes to our release process. Most notably:

- Obviously, as this is the main point of this PR, the build process has
  once again been restricted to only trigger new releases from the
  `master` branch.
- As our CI machinery cannot easily be made to produce multiple releases
  from a single build, the `check_for_release` step will only recognize
  a commit as a release trigger if it changes a single line in the
  `LATEST` file. This restriction comes in addition to the existing one
  that a release commit is only allowed to change either just the
  `LATEST` file or both the `LATEST` and
  `docs/source/support/release-notes.rst` files.
- The docs publication process has been changed to update _all_
  published versions to display the _latest_ release notes page. This
  means that the release notes page will always show you all published
  versions, regardless of which version of the documentation you're
  looking at. This also means that interleaving release notes correctly on
  that page is a manual exercise.
- As per the intention of the new process, the `LATEST` file has been
  updated to contained all existing post-1.0 stable releases. It should
  also include all existing snapshot releases should we have more than one
  at a time (say, should we discover an issue with 1.1.1 that required us
  to work on a 1.1.2).
- The `release.sh` script has been dramatically simplified as I felt it
  was trying to do too much and porting its existing functionality to a
  multi-line `LATEST` file would be too hard.

CHANGELOG_BEGIN
CHANGELOG_END
This commit is contained in:
Gary Verhaegen 2020-05-19 19:18:10 +02:00 committed by GitHub
parent 92a2b5a28c
commit fb6dc904a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 155 additions and 208 deletions

3
LATEST
View File

@ -1 +1,4 @@
021f4af394ceb34d9cdfb64e6ac9b908ca2da0f8 1.2.0-snapshot.20200513.4172.0.021f4af3
7e448d810c1134c39afa2c555e85964b68976446 1.1.1
160936905d393a6f8fb35ea02ad6b3c401820dad 1.0.1
f050da78c9c8727b889bdac286156f19e2f938c4 1.0.0

View File

@ -274,20 +274,41 @@ jobs:
./release.sh check
is_release_commit() {
changes_release_files() {
changed="$(git diff-tree --no-commit-id --name-only -r $(branch_sha) $(fork_sha) | sort)"
stable=$(printf "LATEST\ndocs/source/support/release-notes.rst" | sort)
snapshot="LATEST"
[ "$snapshot" = "$changed" ] || [ "$stable" = "$changed" ]
}
if is_release_commit; then
echo "##vso[task.setvariable variable=is_release;isOutput=true]true"
echo "##vso[task.setvariable variable=trigger_sha;isOutput=true]$(branch_sha)"
echo "##vso[task.setvariable variable=release_sha;isOutput=true]$(cat LATEST | awk '{print $1}')"
echo "##vso[task.setvariable variable=release_tag;isOutput=true]$(cat LATEST | awk '{print $2}')"
changes_one_line_in_latest() {
changed="$(git diff-tree --no-commit-id --numstat -r $(branch_sha) $(fork_sha) -- LATEST | awk '{print $1 "_" $2}')"
add_one="1_0"
change_one="1_1"
[[ "$add_one" == "$changed" || "$change_one" == "$changed" ]]
}
setvar() {
echo "Setting '$1' to '$2'"
echo "##vso[task.setvariable variable=$1;isOutput=true]$2"
}
added_line() {
echo "$(git diff $(branch_sha) $(fork_sha) -- LATEST | tail -n+6 | grep '^\+' | cut -c2-)"
}
if changes_release_files; then
if changes_one_line_in_latest; then
setvar is_release true
setvar trigger_sha $(branch_sha)
setvar release_sha "$(added_line | awk '{print $1}')"
setvar release_tag "$(added_line | awk '{print $2}')"
else
echo "Release commit should only add one version."
exit 1
fi
else
echo "##vso[task.setvariable variable=is_release;isOutput=true]false"
setvar is_release false
fi
name: out
@ -320,8 +341,7 @@ jobs:
dependsOn: [ "check_for_release", "Linux", "macOS", "Windows" ]
condition: and(succeeded(),
eq(dependencies.check_for_release.outputs['out.is_release'], 'true'),
or(eq(variables['Build.SourceBranchName'], 'master'),
startsWith(variables['Build.SourceBranch'], 'refs/heads/release/')))
eq(variables['Build.SourceBranchName'], 'master'))
pool:
vmImage: "Ubuntu-16.04"
variables:
@ -418,6 +438,7 @@ jobs:
title: '$(release_tag)'
addChangeLog: false
isPrerelease: true
releaseNotes: "This is a pre-release. Use at your own risk."
condition: not(eq(variables['skip-github'], 'TRUE'))
- bash: |
set -euo pipefail
@ -452,8 +473,7 @@ jobs:
pool:
vmImage: "Ubuntu-16.04"
condition: and(eq(dependencies.check_for_release.outputs['out.is_release'], 'true'),
or(eq(variables['Build.SourceBranchName'], 'master'),
startsWith(variables['Build.SourceBranch'], 'refs/heads/release/')))
eq(variables['Build.SourceBranchName'], 'master'))
variables:
release_sha: $[ dependencies.check_for_release.outputs['out.release_sha'] ]
release_tag: $[ dependencies.check_for_release.outputs['out.release_tag'] ]

View File

@ -67,8 +67,7 @@ steps:
name: publish_npm_mvn
condition: and(succeeded(),
eq(${{parameters.is_release}}, 'true'),
or(eq(variables['Build.SourceBranchName'], 'master'),
startsWith(variables['Build.SourceBranch'], 'refs/heads/release/')),
eq(variables['Build.SourceBranchName'], 'master'),
eq('${{parameters.name}}', 'linux'))
- bash: |
set -euo pipefail
@ -96,24 +95,21 @@ steps:
name: publish
condition: and(succeeded(),
eq(${{parameters.is_release}}, 'true'),
or(eq(variables['Build.SourceBranchName'], 'master'),
startsWith(variables['Build.SourceBranch'], 'refs/heads/release/')))
eq(variables['Build.SourceBranchName'], 'master'))
- task: PublishPipelineArtifact@0
inputs:
targetPath: $(Build.StagingDirectory)/$(publish.tarball)
artifactName: $(publish.tarball)
condition: and(succeeded(),
eq(${{parameters.is_release}}, 'true'),
or(eq(variables['Build.SourceBranchName'], 'master'),
startsWith(variables['Build.SourceBranch'], 'refs/heads/release/')))
eq(variables['Build.SourceBranchName'], 'master'))
- task: PublishPipelineArtifact@0
inputs:
targetPath: $(Build.StagingDirectory)/$(publish.protos-zip)
artifactName: $(publish.protos-zip)
condition: and(succeeded(),
eq(${{parameters.is_release}}, 'true'),
or(eq(variables['Build.SourceBranchName'], 'master'),
startsWith(variables['Build.SourceBranch'], 'refs/heads/release/')),
eq(variables['Build.SourceBranchName'], 'master'),
eq('${{parameters.name}}', 'linux'))
- task: PublishPipelineArtifact@0
inputs:
@ -121,8 +117,7 @@ steps:
artifactName: $(publish.daml-on-sql)
condition: and(succeeded(),
eq(${{parameters.is_release}}, 'true'),
or(eq(variables['Build.SourceBranchName'], 'master'),
startsWith(variables['Build.SourceBranch'], 'refs/heads/release/')),
eq(variables['Build.SourceBranchName'], 'master'),
eq('${{parameters.name}}', 'linux'))
- task: PublishPipelineArtifact@0
inputs:
@ -130,6 +125,5 @@ steps:
artifactName: $(publish.json-api)
condition: and(succeeded(),
eq(${{parameters.is_release}}, 'true'),
or(eq(variables['Build.SourceBranchName'], 'master'),
startsWith(variables['Build.SourceBranch'], 'refs/heads/release/')),
eq(variables['Build.SourceBranchName'], 'master'),
eq('${{parameters.name}}', 'linux'))

View File

@ -51,21 +51,18 @@ steps:
DAML_SDK_RELEASE_VERSION: ${{parameters.release_tag}}
condition: and(succeeded(),
eq(${{parameters.is_release}}, 'true'),
or(eq(variables['Build.SourceBranchName'], 'master'),
startsWith(variables['Build.SourceBranch'], 'refs/heads/release/')))
eq(variables['Build.SourceBranchName'], 'master'))
- task: PublishPipelineArtifact@0
condition: and(succeeded(),
eq(${{parameters.is_release}}, 'true'),
or(eq(variables['Build.SourceBranchName'], 'master'),
startsWith(variables['Build.SourceBranch'], 'refs/heads/release/')))
eq(variables['Build.SourceBranchName'], 'master'))
inputs:
targetPath: $(Build.StagingDirectory)/$(publish.installer)
artifactName: $(publish.installer)
- task: PublishPipelineArtifact@0
condition: and(succeeded(),
eq(${{parameters.is_release}}, 'true'),
or(eq(variables['Build.SourceBranchName'], 'master'),
startsWith(variables['Build.SourceBranch'], 'refs/heads/release/')))
eq(variables['Build.SourceBranchName'], 'master'))
inputs:
targetPath: $(Build.StagingDirectory)/$(publish.tarball)
artifactName: $(publish.tarball)

View File

@ -12,6 +12,7 @@ import qualified Data.Aeson as JSON
import qualified Data.ByteString.UTF8 as BS
import qualified Data.ByteString.Lazy.UTF8 as LBS
import qualified Data.CaseInsensitive as CI
import qualified Data.Foldable
import qualified Data.HashMap.Strict as H
import qualified Data.List as List
import qualified Data.List.Extra as List
@ -107,13 +108,14 @@ to_v s = case Split.splitOn "-" s of
_ -> error $ "Invalid data, needs manual repair. Got this for a version string: " <> s
build_docs_folder :: String -> [GitHubVersion] -> String -> IO String
build_docs_folder path versions latest = do
build_docs_folder path versions current = do
restore_sha $ do
let old = path </> "old"
let new = path </> "new"
shell_ $ "mkdir -p " <> new
shell_ $ "mkdir -p " <> old
download_existing_site_from_s3 old
latest_release_notes_sha <- shell "git log -n1 --format=%H master -- LATEST"
documented_versions <- Maybe.catMaybes <$> Traversable.for versions (\gh_version -> do
let version = name gh_version
putStrLn $ "Building " <> version <> "..."
@ -128,7 +130,7 @@ build_docs_folder path versions latest = do
then do
putStrLn " Found. Too old to rebuild, copying over..."
copy (old </> version) $ new </> version
return $ Just gh_version
return $ Just (gh_version, False)
else do
putStrLn " Too old to rebuild and no existing version. Skipping."
return Nothing
@ -143,11 +145,11 @@ build_docs_folder path versions latest = do
then do
putStrLn " Found. No reliable checksum; copying over and hoping for the best..."
copy (old </> version) $ new </> version
return $ Just gh_version
return $ Just (gh_version, False)
else do
putStrLn " Not found. Building..."
build version new
return $ Just gh_version
build version new latest_release_notes_sha
return $ Just (gh_version, True)
else if old_version_exists
then do
-- Note: this checks for upload errors; this is NOT in any way
@ -159,21 +161,31 @@ build_docs_folder path versions latest = do
then do
putStrLn " Checks, reusing existing."
copy (old </> version) $ new </> version
return $ Just gh_version
return $ Just (gh_version, False)
else do
putStrLn " Check failed. Rebuilding..."
build version new
return $ Just gh_version
build version new latest_release_notes_sha
return $ Just (gh_version, True)
else do
putStrLn " Not found. Building..."
build version new
return $ Just gh_version)
putStrLn $ "Copying latest (" <> latest <> ") to top-level..."
copy (new </> latest </> "*") (new <> "/")
build version new latest_release_notes_sha
return $ Just (gh_version, True))
putStrLn $ "Copying current (" <> current <> ") to top-level..."
copy (new </> current </> "*") (new <> "/")
putStrLn "Creating versions.json..."
let (releases, snapshots) = List.partition (not . prerelease) documented_versions
create_versions_json releases (new </> "versions.json")
create_versions_json snapshots (new </> "snapshots.json")
let (releases, snapshots) = List.partition (not . prerelease . fst) documented_versions
create_versions_json (map fst releases) (new </> "versions.json")
create_versions_json (map fst snapshots) (new </> "snapshots.json")
case filter snd documented_versions of
((newly_built,_):_) -> do
putStrLn $ "Copying release notes from " <> name newly_built <> " to all other versions..."
let p v = new </> name v </> "support" </> "release-notes.html"
let top_level_release_notes = new </> "support" </> "release-notes.html"
shell_ $ "cp " <> p newly_built <> " " <> top_level_release_notes
Data.Foldable.for_ documented_versions $ \(gh_version, _) -> do
shell_ $ "cp " <> top_level_release_notes <> " " <> p gh_version
_ -> do
putStrLn "No version built, so no release page copied."
return new
where
restore_sha io =
@ -185,14 +197,14 @@ build_docs_folder path versions latest = do
shell_ $ "aws s3 sync s3://docs-daml-com/ " <> path
exists dir = Directory.doesDirectoryExist dir
checksums path = do
let cmd = "cd " <> path <> "; sha256sum -c checksum"
let cmd = "cd " <> path <> "; sed -i ':support/release-notes.html:d' checksum; sha256sum -c checksum"
(code, _, _) <- shell_exit_code cmd
case code of
Exit.ExitSuccess -> return True
_ -> return False
copy from to = do
shell_ $ "cp -r " <> from <> " " <> to
build version path = do
build version path latest_sha = do
shell_ $ "git checkout v" <> version
-- Maven does not accept http connections anymore; this patches the
-- scala rules for Bazel to use https instead. This is not needed
@ -207,25 +219,24 @@ build_docs_folder path versions latest = do
-- Starting after 0.13.54, we have changed the way in which we
-- trigger releases. Rather than releasing the current commit by
-- changing the VERSION file, we now mark an existing commit as the
-- source code for a release by changing the LATEST file. However,
-- release notes still need to be taken from the release commit
-- (i.e. the one that changes the LATEST file, not the one being
-- pointed to).
-- source code for a release by changing the LATEST file. This
-- raises the question of the release notes: as we tag a commit
-- from the past, and keep the changelog outside of the worktree
-- (in commit messages), that means that commit cannot contain its
-- own release notes. We have decided to resolve that conundrum by
-- always including the release notes from the most recent release
-- in all releases.
else do
-- The release-triggering commit does not have a tag, so we
-- need to find it by walking through the git history of the
-- LATEST file.
sha <- find_commit_for_version version
Control.Exception.bracket
(shell_ $ "git checkout " <> sha <> " -- docs/source/support/release-notes.rst")
(\_ -> shell_ "git reset --hard")
(\_ -> build_helper version path)
Control.Exception.bracket_
(shell_ $ "git checkout " <> latest_sha <> " -- docs/source/support/release-notes.rst")
(shell_ "git reset --hard")
(build_helper version path)
build_helper version path = do
robustly_download_nix_packages version
shell_ $ "DAML_SDK_RELEASE_VERSION=" <> version <> " bazel build //docs:docs"
shell_ $ "mkdir -p " <> path </> version
shell_ $ "tar xzf bazel-bin/docs/html.tar.gz --strip-components=1 -C" <> path </> version
checksums <- shell $ "cd " <> path </> version <> "; find . -type f -exec sha256sum {} \\;"
checksums <- shell $ "cd " <> path </> version <> "; find . -type f -exec sha256sum {} \\; | grep -v 'support/release-notes.html'"
writeFile (path </> version </> "checksum") checksums
create_versions_json versions path = do
-- Not going through Aeson because it represents JSON objects as
@ -238,20 +249,6 @@ build_docs_folder path versions latest = do
& \s -> "{" <> s <> "}"
writeFile path versions_json
find_commit_for_version :: String -> IO String
find_commit_for_version version = do
release_commits <- lines <$> shell "git log --format=%H --all -- LATEST"
ver_sha <- init <$> (shell $ "git rev-parse v" <> version)
let expected = ver_sha <> " " <> version
matching <- Maybe.catMaybes <$> Traversable.for release_commits (\sha -> do
latest <- init <$> (shell $ "git show " <> sha <> ":LATEST")
if latest == expected
then return $ Just sha
else return Nothing)
case matching of
[sha] -> return sha
_ -> error $ "Expected single commit to match release " <> version <> ", but instead found: " <> show matching
fetch_s3_versions :: IO (Set.Set Version, Set.Set Version)
fetch_s3_versions = do
releases <- fetch "versions.json"
@ -281,13 +278,12 @@ push_to_s3 doc_folder = do
<> " --distribution-id E1U753I56ERH55"
<> " --paths '/*'"
data GitHubVersion = GitHubVersion { prerelease :: Bool, tag_name :: String, notes :: String, published_at :: String } deriving Show
data GitHubVersion = GitHubVersion { prerelease :: Bool, tag_name :: String, notes :: String } deriving Show
instance JSON.FromJSON GitHubVersion where
parseJSON = JSON.withObject "GitHubVersion" $ \v -> GitHubVersion
<$> v JSON..: Text.pack "prerelease"
<*> v JSON..: Text.pack "tag_name"
<*> v JSON..:? Text.pack "body" JSON..!= ""
<*> v JSON..: Text.pack "published_at"
name :: GitHubVersion -> String
name gh = tail $ tag_name gh

View File

@ -5,6 +5,8 @@
set -euo pipefail
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
uhoh() {
echo "
It looks like this script failed to complete. Please check the status
@ -13,31 +15,32 @@ uhoh() {
trap uhoh EXIT
CURRENT=$(cat LATEST | awk '{print $2}')
STABLE_REGEX="\d+\.\d+\.\d+"
VERSION_REGEX="^${STABLE_REGEX}(-snapshot\.\d{8}\.\d+(\.\d+)?\.[0-9a-f]{8})?$"
release_sha() {
git show $1:LATEST | gawk '{print $1}'
}
release_version() {
git show $1:LATEST | gawk '{print $2}'
function file_ends_with_newline() {
[[ $(tail -c1 "$1" | wc -l) -gt 0 ]]
}
check() {
if ! echo $(release_version HEAD) | grep -q -P $VERSION_REGEX; then
echo "Invalid version number in LATEST file, needs manual correction."
if ! file_ends_with_newline LATEST; then
echo "LATEST file does not end with newline. Please correct."
exit 1
else
echo -n "Valid version number ("
if is_stable $(release_version HEAD); then
echo -n "stable"
else
echo -n "snapshot"
fi
echo ")."
fi
while read line; do
sha=$(echo "$line" | gawk '{print $1}')
ver=$(echo "$line" | gawk '{print $2}')
if ! echo "$ver" | grep -q -P $VERSION_REGEX; then
echo "Invalid version number in LATEST file, needs manual correction."
exit 1
fi
if ! is_stable $ver; then
if ! echo "$ver" | grep -q -P "^${STABLE_REGEX}$(make_snapshot $sha)$"; then
echo "$ver does not match $sha, please correct."
exit 1
fi
fi
done < LATEST
}
is_stable() {
@ -50,40 +53,7 @@ make_snapshot() {
local commit_date=$(git log -n1 --format=%cd --date=format:%Y%m%d $sha)
local number_of_commits=$(git rev-list --count $sha)
local commit_sha_8=$(git log -n1 --format=%h --abbrev=8 $sha)
local prerelease="snapshot.$commit_date.$number_of_commits.0.$commit_sha_8"
if is_stable "$(release_version HEAD)"; then
local stable="$(release_version HEAD)"
else
local stable=$(echo "$(release_version HEAD)" | grep -o -P "^$STABLE_REGEX")
fi
echo "$sha $stable-$prerelease" > LATEST
echo "Updated LATEST file."
}
parse_range() {
case $1 in
head)
git rev-parse HEAD
;;
latest)
release_sha HEAD
;;
previous)
release_sha $(git log -n2 --format=%H LATEST | sed 1d)
;;
stable)
for sha in $(git log --format=%H LATEST | sed 1d); do
if is_stable $(release_version $sha); then
release_sha $sha
break
fi
done
;;
*)
display_help
exit 1
;;
esac
echo "-snapshot.$commit_date.$number_of_commits.0.$commit_sha_8"
}
display_help() {
@ -91,33 +61,17 @@ display_help() {
This script is meant to help with managing releases. Usage:
$0 snapshot SHA
Updates the LATEST file to point to the given SHA (which must be a
valid git reference to a commit on origin/master). If the current
version defined in LATEST is already a snapshot, keeps the stable part
of the version unchanged; otherwise, increments the patch number.
Prints the snapshot version suffix for the given commit. For example:
$ $0 snapshot cc880e2
-snapshot.20200513.4174.0.cc880e29
Any non-ambiguous git commit reference can be given as SHA.
$0 check
Checks that the LATEST file is well-formed and prints a message saying
whether the latest release is considered stable or snapshot.
$0 changes <start> <end>
Prints the changes between start and end. In this context, possible
values are, in order:
head
The current commit.
latest
The commit pointed at by the LATEST file in the current commit.
previous
The most recent release (stable or snapshot) before the current
one.
stable
The most recent stable release before the current one.
Specifying them out of order is not supported.
Checks that each line of the LATEST file is well-formed.
Any other invocation will display this help message.
Note: at the moment, changing the version string for a stable release is left
as a manual exercice, but that may change in the future.
EOF
}
@ -139,14 +93,6 @@ case $1 in
check)
check
;;
changes)
if [ -z "${2+x}" ] || [ -z "${3+x}" ]; then
display_help
exit 1
else
./unreleased.sh $(parse_range $2)..$(parse_range $3)
fi
;;
*)
display_help
;;

View File

@ -2,7 +2,7 @@
First, you need to decide whether you are making a technical snapshot
("prerelease" at the github level, hereafter "snapshot") or an officially
supported release (hereafter "stable release"). For the latter, there are
supported release (hereafter "stable release"). For the latter, there are
extra steps marked as **[STABLE]** in the following instructions. You have to
skip those if you are making a snapshot release, that is, one intended mostly
for internal use and early testing, but which makes no promises about future
@ -10,44 +10,50 @@ compatibility.
In either case, before going through the following list, you need to know which
commit you want to create the release from, `$SHA`. For a stable release, it is
highly recommended that this be the same commit as the latest existing
snapshot, so we "bless" an existing, tested version of the SDK rather than try
our luck with a random new one. For a snapshot, this should generally be the
latest commit on master.
highly recommended that this be the same commit as an existing snapshot, and
these instructions will be written from that perspective.
Valid commits for a release should come from either the `master` branch or one
of the support `release/a.b.x` branches (e.g. `release/1.0.x` branch is for
patches we backport to the 1.0 release branch).
> **IMPORTANT**: If the release fails, please do not just abandon it. There are
> some cleanup steps that need to be taken.
1. **[STABLE]** Coordinate with the product and marketing teams to define
release highlights, tweets, blog posts, as well as timeline for publishing
the release. Define a version number, `$VERSION`. The following command may
be useful as a starting point; it will list all changes between the previous
stable release and the latest snapshot release:
the release. Define a version number, `$VERSION`. As a starting point, find
out the sha of the reference version (previous stable release in the same
release branch), say `$PREV_SHA`, and run:
```
./release.sh changes stable latest
./unreleased.sh $PREV_SHA $SHA
```
1. Pull the latest master branch of the `daml` repository and create a new,
clean branch off it.
clean branch off it. Now, we have three possible cases:
- For a snapshot, run `./release.sh snapshot HEAD`.
- If applicable (e.g. latest release was a stable one), edit `LATEST` to
update the release "version". For example, change:
```
6ea118d6142d2a937286b0a7bf9846dbcdb1751b 0.13.56-snapshot.20200318.3529.0.6ea118d6
```
to:
```
6ea118d6142d2a937286b0a7bf9846dbcdb1751b 0.13.57-snapshot.20200318.3529.0.6ea118d6
```
- For a stable release, run `echo "$SHA $VERSION" > LATEST`.
- Ideally, for a stable release, the resulting change is only to cut off
the prerelease part of the version number (the `-snapshot...`).
- For a stable release, just remove the snapshot suffix from the latest
entry for that branch in the LATEST file, replacing the existing line.
- If you are making the first snapshot for a new target version (i.e. there
is no snapshot for it yet), add a new line for that version. It does not
matter to the process where that line is, but try to keep versions sorted
by version number.
- If you are making a new snapshot for an existing target version, i.e. the
stable part of the version number is the same, replace the existing line.
In both of the latter cases, you can get the "snapshot" part of the version
tag by running `./release.sh snapshot $SHA`.
1. **[STABLE]** In `docs/source/support/release-notes.rst`, add a new header
and label for the new version. (See previous releases as examples.)
Note that the release notes page is not version dependent, i.e. you are
editing the one and only release notes page. If the release your are making
is a patch on a support branch, it should be included in-between the next
"minor" release and the latest patch to the branch your are targeting.
Once we are ready to make a release stable, preliminary release
notes will already have been published to the blog, e.g., the
preliminary release notes for 1.0 were at
@ -70,7 +76,7 @@ latest commit on master.
release. In particular, this means that in Rst terminology all
of these are external links.
1. Pandoc does not seem to preserve markup of inline code blocks so
you will have to manually add wrap them in double backslashes.
you will have to manually wrap them in double backslashes.
1. Once this is done, create a GitHub pull request (PR) with the above changes
to the `LATEST` and (for a stable release) `release-notes.rst` files. It is
@ -79,6 +85,10 @@ latest commit on master.
should be able to add the label and "rerun failed checks" in a few seconds;
there is no need to restart an entire build cycle.
1. Once the PR has built, check that it was considered a release build by our
CI. You can do that by looking at the output of the `check_for_release`
build step.
1. Get a review and approval on your PR and then merge it into master.
**[STABLE]** For a stable release, the approval **MUST** be from the team
lead of the Language, Runtime or Product team.
@ -321,34 +331,15 @@ latest commit on master.
page](https://github.com/digital-asset/daml/releases). Mention why it is bad
as a comment on your PR, and **stop the process here**.
1. Add the label `Standard-Change` to your PR.
1. Go to [the releases page](https://github.com/digital-asset/daml/releases)
and edit the release to look better. For both types of release, the release
title should be the version number (i.e. same as the git tag). For a
snapshot, the message should be set to
> This is a snapshot release. Use at your own risk.
For a stable release, the message should contain the team-lead-approved
release notes, and the "prerelease" checkbox should be unticked.
1. **[STABLE]** Go to [the releases page](https://github.com/digital-asset/daml/releases)
and add the release notes. This unfortunately involves translating the
release notes from rst to markdown. Once the release has been adequately
tested, untick the `pre-release` box.
1. Announce the release on the relevant internal Slack channels (#product-daml,
\#team-daml). Add release notes in a thread under your announcement. For a
stable release, these are the notes decided with the product team; for a
snapshot release, include both the changes in this release (i.e. since the
last snapshot) and the complete list of changes since the last stable
release. Use the raw output of `unreleased.sh`.
You can produce the changes since the previous (snapshot or stable) release
by running:
```
./release.sh changes previous latest
```
and the changes between the latest stable and the previous release with:
```
./release.sh changes stable previous
```
\#team-daml). For a stable release, direct people to the release blog post;
for a prerelease, you can include the raw output of the `unreleased.sh`
script as explained above.
1. **[STABLE]** Coordinate with product (& marketing) for the relevant public
announcements (public Slack, Twitter, etc.).