mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-19 16:57:40 +03:00
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 commit681c862d
. On May 6, we decided to take a new snapshot as the RC for 1.1.0; we changed `LATEST` in `master` to designate7e448d81
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 build7e448d81
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 commit7e448d81
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 to681c862d
. 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:
parent
92a2b5a28c
commit
fb6dc904a4
3
LATEST
3
LATEST
@ -1 +1,4 @@
|
||||
021f4af394ceb34d9cdfb64e6ac9b908ca2da0f8 1.2.0-snapshot.20200513.4172.0.021f4af3
|
||||
7e448d810c1134c39afa2c555e85964b68976446 1.1.1
|
||||
160936905d393a6f8fb35ea02ad6b3c401820dad 1.0.1
|
||||
f050da78c9c8727b889bdac286156f19e2f938c4 1.0.0
|
||||
|
@ -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'] ]
|
||||
|
@ -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'))
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
110
release.sh
110
release.sh
@ -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
|
||||
;;
|
||||
|
@ -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.).
|
||||
|
Loading…
Reference in New Issue
Block a user