Skip to content
Snippets Groups Projects
update-production 4.17 KiB
Newer Older
  • Learn to ignore specific revisions
  • #!/usr/bin/env nix-shell
    
    #!nix-shell -i bash -p git curl python3
    
    
    set -eux -o pipefail
    
    main() {
        local TOKEN=$1
        shift
        local SERVER_URL=$1
        shift
        local PROJECT_ID=$1
        shift
        local SOURCE_BRANCH=$1
        shift
        local TARGET_BRANCH=$1
        shift
    
    
        # Make sure the things we want to talk about are locally known.  GitLab
        # seems to prefer to know about as few refs as possible.
        checkout_git_ref "$SOURCE_BRANCH"
        checkout_git_ref "$TARGET_BRANCH"
    
    
        # If there have been no changes we'll just abandon this update.
    
        if ! ensure_changes "$SOURCE_BRANCH" "$TARGET_BRANCH"; then
    	echo "No changes."
    	exit 0
        fi
    
        local NOTES=$(describe_update "$SOURCE_BRANCH" "$TARGET_BRANCH")
    
    
        create_merge_request "$TOKEN" "$SERVER_URL" "$PROJECT_ID" "$SOURCE_BRANCH" "$TARGET_BRANCH" "$NOTES"
    }
    
    
    checkout_git_ref() {
        local REF=$1
        shift
    
        git fetch origin "$REF"
    }
    
    
    ensure_changes() {
        local SOURCE_BRANCH=$1
        shift
        local TARGET_BRANCH=$1
        shift
    
    
        if [ "$(git rev-parse origin/"$SOURCE_BRANCH")" = "$(git rev-parse origin/"$TARGET_BRANCH")" ]; then
    
    describe_merge_request() {
        git show $rev | grep 'See merge request' | sed -e 's/See merge request //' | tr -d '[:space:]'
    }
    
    describe_merge_requests() {
        local RANGE=$1
        shift
        local TARGET=$1
        shift
    
        # Find all of the relevant merge revisions
        local onelines=$(git log --merges --first-parent -m --oneline "$RANGE" | grep "into '$TARGET'")
    
        # Describe each merge revision
        local IFS=$'\n'
        for line in $onelines; do
    	local rev=$(echo "$line" | cut -d ' ' -f 1)
    	echo -n "* "
    	describe_merge_request $rev
    	echo
        done
    }
    
    
        local SOURCE_BRANCH=$1
        shift
        local TARGET_BRANCH=$1
        shift
    
    
        # Since production production (target) should not diverge from develop
        # (source) it is fine to use `..` instead of `...` in the git ranges here.
        # `...` encounters problems related to discovering the merge base because
        # of the way GitLab manages the git checkout on CI (I think).
    
        local NOTES=$(git diff origin/"$TARGET_BRANCH"..origin/"$SOURCE_BRANCH" -- DEPLOYMENT-NOTES.rst)
    
    
        # There often are no notes and that makes for boring reading so toss in a
        # diffstat as well.
    
        local DIFFSTAT=$(git diff --stat origin/"$TARGET_BRANCH"..origin/"$SOURCE_BRANCH")
    
    
        local WHEN=$(git log --max-count=1 --format='%cI' origin/"$TARGET_BRANCH")
    
    
        # Describe all of the MRs that were merged into the source branch that are
        # about to be merged into the target branch.
    
        local MR=$(describe_merge_requests origin/"$TARGET_BRANCH"..origin/"$SOURCE_BRANCH" "$SOURCE_BRANCH")
    
        echo "\
    Changes from $SOURCE_BRANCH since $WHEN
    =======================================
    
    Deployment Notes
    ----------------
    \`\`\`
    $NOTES
    \`\`\`
    
    
    Included Merge Requests
    -----------------------
    $MR
    
    
    Diff Stat
    ---------
    \`\`\`
    $DIFFSTAT
    \`\`\`
    "
    
    }
    
    create_merge_request() {
        local TOKEN=$1
        shift
        local SERVER_URL=$1
        shift
        local PROJECT_ID=$1
        shift
        # THe source branch of the MR.
        local SOURCE_BRANCH=$1
        shift
        # The target branch of the MR.
        local TARGET_BRANCH=$1
        shift
        local NOTES=$1
        shift
    
        local BODY=$(python3 -c '
    import sys, json
    print(json.dumps({
        "id": sys.argv[1],
        "source_branch": sys.argv[2],
        "target_branch": sys.argv[3],
        "remove_source_branch": True,
        "title": f"update {sys.argv[3]}",
    
        "description": sys.argv[4],
    
    }))
    ' "$PROJECT_ID" "$SOURCE_BRANCH" "$TARGET_BRANCH" "$NOTES")
    
        curl --verbose -X POST --data "${BODY}" --header "Content-Type: application/json" --header "PRIVATE-TOKEN: ${TOKEN}" "${SERVER_URL}/api/v4/projects/${PROJECT_ID}/merge_requests"
    }
    
    # Pull the GitLab token from the environment here so we can work with them as
    # arguments everywhere else.  They're passed to us in the environment because
    # *maybe* this is *slightly* safer than passing them in argv.
    
    #
    # The name is slightly weird because it is shared with the update-nixpkgs job.
    TOKEN="$UPDATE_NIXPKGS_PRIVATE_TOKEN"
    
    
    # Before proceeding, remove the secrets from our environment so we don't pass
    # them to child processes - none of which need them.
    
    unset UPDATE_NIXPKGS_PRIVATE_TOKEN