--- name: Upstream Sync Workflow 'on': workflow_call: inputs: release_series: description: 'The OpenStack release series you wish to sync against.' required: true type: string branch_prefix: description: 'The prefix of the upstream branch you want to sync against.' required: false type: string default: stable fallback_branch_prefix: description: 'The fallback prefix of the upstream branch you want to sync against.' required: false type: string default: unmaintained upstream: description: Upstream repository on GitHub (owner/repo) type: string required: false sync_tags: description: 'Whether to synchronize tags from upstream' required: false type: boolean default: true env: GITHUB_TOKEN: ${{github.token}} DOWNSTREAM_OWNER: stackhpc UPSTREAM_OWNER: openstack jobs: upstream-sync: runs-on: ubuntu-latest steps: - name: Get upstream SHA id: get_upstream_sha run: | set +e function get_sha { ref=$1 upstream_repo=$2 gh api \ -H "Accept: application/vnd.github.v3+json" \ "/repos/${upstream_repo}/commits/${ref}" --jq ".sha" } upstream="${{ inputs.upstream }}" if [[ -z "$upstream" ]]; then upstream="${{env.UPSTREAM_OWNER}}/$(basename $(pwd))" fi upstream_ref="${{inputs.branch_prefix}}/${{inputs.release_series}}" upstream_sha=$(get_sha $upstream_ref $upstream) result=$? if [[ $result -ne 0 ]] && [[ -n "${{inputs.fallback_branch_prefix}}" ]]; then echo "Failed to get SHA using standard branch prefix. Trying fallback." upstream_ref="${{inputs.fallback_branch_prefix}}/${{inputs.release_series}}" upstream_sha=$(get_sha $upstream_ref $upstream) result=$? fi if [[ $result -ne 0 ]]; then echo "Failed to get SHA using standard or fallback branch prefixes. Checking for EOL tag." upstream_ref="${{inputs.release_series}}-eol" upstream_sha=$(get_sha $upstream_ref $upstream) result=$? if [[ $result -ne 0 ]]; then echo "Unable to find EOL tag. Trying master branch" upstream_ref="master" upstream_sha=$(get_sha $upstream_ref $upstream) result=$? if [[ $result -ne 0 ]]; then echo "Unable to find master branch - Failing" exit 1 fi fi fi echo "upstream_ref=$upstream_ref" >> $GITHUB_OUTPUT echo "result=$upstream_sha" >> $GITHUB_OUTPUT - name: Check if downstream branch exists if: steps.get_upstream_sha.outputs.result != '' id: check_if_downstream_branch_exists run: | api_path="/repos/${{env.DOWNSTREAM_OWNER}}/$(basename $(pwd))/branches/stackhpc/${{inputs.release_series}}" response=$(gh api -H "Accept: application/vnd.github.v3+json" $api_path --silent --include) || true if [[ "$response" =~ "HTTP/2.0 200 OK" ]]; then echo "result=true" >> $GITHUB_OUTPUT elif [[ "$response" =~ "HTTP/2.0 404 Not Found" ]]; then echo "result=false" >> $GITHUB_OUTPUT else exit 1 fi - name: Create missing downstream branch if: steps.check_if_downstream_branch_exists.outputs.result == 'false' run: | gh api \ --method POST \ -H "Accept: application/vnd.github.v3+json" \ "/repos/${{env.DOWNSTREAM_OWNER}}/$(basename $(pwd))/git/refs" \ -f ref='refs/heads/stackhpc/${{inputs.release_series}}' \ -f sha=${{steps.get_upstream_sha.outputs.result}} - name: Check if upstream is ahead of downstream if: steps.check_if_downstream_branch_exists.outputs.result == 'true' id: check_if_ahead run: | ahead_by=$(gh api \ -H "Accept: application/vnd.github.v3+json" \ "/repos/${{env.DOWNSTREAM_OWNER}}/$(basename $(pwd))"\ "/compare/stackhpc/${{inputs.release_series}}..."\ "${{env.UPSTREAM_OWNER}}:${{steps.get_upstream_sha.outputs.result}}" --jq '.ahead_by') echo "result=$ahead_by" >> $GITHUB_OUTPUT - name: Create copy of the upstream branch if: steps.check_if_ahead.outputs.result > 0 run: | gh api \ --method POST \ -H "Accept: application/vnd.github.v3+json" \ "/repos/${{env.DOWNSTREAM_OWNER}}/$(basename $(pwd))/git/refs" \ -f ref="refs/heads/upstream/${{inputs.release_series}}-$(date +%F)" \ -f sha=${{steps.get_upstream_sha.outputs.result}} - name: Create a pull request if: steps.check_if_ahead.outputs.result > 0 id: create_pull_request run: | pull_request_url=$(gh api \ --method POST \ -H "Accept: application/vnd.github.v3+json" \ /repos/${{env.DOWNSTREAM_OWNER}}/$(basename $(pwd))/pulls \ -f title="Synchronise ${{inputs.release_series}} with upstream" \ -f body="This PR contains a snapshot of ${{inputs.release_series}} from upstream ${{steps.get_upstream_sha.outputs.upstream_ref}}." \ -f head="${{env.DOWNSTREAM_OWNER}}:upstream/${{inputs.release_series}}-$(date +%F)" \ -f base="stackhpc/${{inputs.release_series}}" --jq '.url') echo "result=$(basename $pull_request_url)" >> $GITHUB_OUTPUT - name: Add labels to pull request if: steps.check_if_ahead.outputs.result > 0 run: | api_path="https://api.github.com/repos/${{env.DOWNSTREAM_OWNER}}\ /$(basename $(pwd))/issues/${{steps.create_pull_request.outputs.result}}/labels" curl \ -X POST \ -H "Authorization: token ${{env.GITHUB_TOKEN}}" \ -H "Accept: application/vnd.github.v3+json" \ $api_path \ -d '{"labels":["automated","synchronisation"]}' - name: Sync tags from upstream to downstream if: ${{ inputs.sync_tags }} run: | upstream="${{ inputs.upstream }}" if [[ -z "$upstream" ]]; then upstream="${{env.UPSTREAM_OWNER}}/$(basename $(pwd))" fi downstream_repo="${{env.DOWNSTREAM_OWNER}}/$(basename $(pwd))" # Get all upstream tags gh api --paginate \ "/repos/${upstream}/git/refs/tags" \ --jq '.[] | "\(.ref) \(.object.sha)"' | \ while read -r ref sha; do echo "Checking tag: $ref" # Check if tag exists in downstream if gh api "/repos/${downstream_repo}/git/${ref}" &>/dev/null; then echo "Tag already exists, skipping" else echo "Creating tag: $ref" gh api --method POST \ "/repos/${downstream_repo}/git/refs" \ -f "ref=$ref" \ -f "sha=$sha" fi done