Repository navigation
190 lines (170 loc) · 7.29 KB
/
Copy pathfledge.yaml
File metadata and controls
190 lines (170 loc) · 7.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
name: fledge
on:
# for manual triggers
workflow_dispatch:
inputs:
pr:
description: "Create PR"
required: false
type: boolean
default: false
push:
branches:
- main
- master
paths:
- ".github/workflows/fledge.yaml"
# Daily, and deliberately hours ahead of `rcc` (`10 1 * * *`).
#
# A push made with `GITHUB_TOKEN` raises no events, so a bump that lands on the
# default branch triggers nothing and it is the scheduled `rcc` run that checks
# it. That only works while the bump is already in place when `rcc` starts.
# 40 minutes was not enough of a margin: GitHub delays each schedule on its own,
# by tens of minutes and independently per workflow, which had squeezed the gap
# to 23 minutes in the busiest repository of this kit -- and where the default
# branch cannot be pushed, the bump only lands once the pull request below has
# merged, which waits for a full `rcc` smoke test.
#
# The minute is off the hour and off the half hour on purpose; those are the
# most contended, and the most delayed.
schedule:
- cron: "40 21 * * *"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.head_ref || '' }}-${{ github.base_ref || '' }}
cancel-in-progress: true
permissions: {}
jobs:
check_news:
runs-on: ubuntu-26.04
timeout-minutes: 15 # longest run seen: 1 min
permissions:
contents: read
outputs:
should_run: ${{ steps.check.outputs.should_run }}
steps:
# Reads NEWS.md through the API instead of a full checkout, for speed,
# which is also why the action is named in full: a local
# `./.github/workflows/...` reference would need the checkout back.
- name: Check if not forked and NEWS.md mentions fledge
id: check
uses: cynkra/cynkratemplate/.github/actions/fledge-check-news@main
with:
gh-token: ${{ secrets.GITHUB_TOKEN }}
fledge:
runs-on: ubuntu-26.04
timeout-minutes: 60 # longest run seen: 16 min
needs: check_news
if: needs.check_news.outputs.should_run == 'true'
permissions:
contents: write
pull-requests: write
actions: write
env:
FLEDGE_GHA_CI: true
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
fetch-tags: true
- name: Configure the Git identity
uses: cynkra/cynkratemplate/.github/actions/git-identity@main
- name: Update apt
run: |
sudo apt-get update
shell: bash
- name: Install R and the package dependencies
uses: cynkra/cynkratemplate/.github/actions/install@main
with:
token: ${{ secrets.GITHUB_TOKEN }}
packages: ${{ github.repository == 'cynkra/fledge' && 'local::.' || 'cynkra/fledge' }}
cache-version: fledge-1
- name: Bump the version, pushing to the default branch where that is allowed
id: bump
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
# `workflow_dispatch` can ask for the pull request route regardless.
FORCE_PR: ${{ inputs.pr }}
run: |
## -- Bump the version --
# A pull request is only needed where the default branch cannot be
# pushed, and no API answers that question. `GET /repos/.../rulesets`,
# which this step used to count, says nothing about *this* token; nor
# does `GET /repos/.../rules/branches/{branch}`, which reports a
# branch's rules whether or not the caller bypasses them -- checked
# against a repository whose ruleset grants an always-bypass that the
# caller holds, and the rule is listed all the same. So push, and let
# the remote answer: `fledge:::push_head()` compares the local commit
# with the upstream one afterwards and aborts when the remote did not
# move, which is the rejection this turns into a route.
gha_output <- function(...) {
cat(sprintf(...), file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE)
}
if (!fledge::bump_version(which = "dev", no_change_behavior = "noop")) {
gha_output("bumped=false\n")
quit(save = "no")
}
gha_output("bumped=true\n")
if (Sys.getenv("FORCE_PR") == "true") {
# Commit and tag locally, and leave the push to the fallback below.
fledge::finalize_version()
gha_output("pushed=false\n")
quit(save = "no")
}
pushed <- tryCatch(
{
fledge::finalize_version(push = TRUE)
TRUE
},
error = function(e) {
message("Could not push the bump to the default branch, opening a pull request instead:")
message(conditionMessage(e))
FALSE
}
)
gha_output("pushed=%s\n", if (pushed) "true" else "false")
shell: Rscript {0}
# Nothing is triggered where the push above succeeded: an event raised by
# `GITHUB_TOKEN` starts no workflow, so the bump waits for the scheduled
# `rcc` run, which is what the cron at the top of this file makes room for.
- name: Open and auto-merge a pull request where it could not
if: steps.bump.outputs.bumped == 'true' && steps.bump.outputs.pushed != 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BASE: ${{ github.event.repository.default_branch }}
run: |
## -- Open and auto-merge a pull request --
set -euxo pipefail
git switch -c fledge
git push -f -u origin HEAD
# `finalize_version()` tags the commit, and the direct push aborted
# before it got to the tag.
tag=$(git tag --points-at HEAD | head -n 1)
if [ -n "${tag}" ]; then
git push -f origin "refs/tags/${tag}"
fi
# The pull request from an earlier night may still be open, when its
# checks never ran or never passed, and the force-push above has
# already moved it to this bump. `gh pr create` fails for a branch
# that has one, and under `set -e` that used to skip the two calls
# below -- the ones that get it checked and merged -- so it stayed
# open, and this step failed, every night after. Reuse it instead,
# retitled, since a squash merge takes its message from the title.
pr=$(gh pr list --head fledge --base "${BASE}" --state open --json url --jq '.[0].url // empty')
if [ -n "${pr}" ]; then
gh pr edit "${pr}" --title "$(git log -1 --format=%s)" --body "$(git log -1 --format=%b)"
else
pr=$(gh pr create --base "${BASE}" --head fledge --fill-first)
fi
# This one does have to be asked for. The pull request is gated on the
# `rcc` status, and the branch push above raised no event either.
gh workflow run rcc -f ref="$(git rev-parse HEAD)"
if [ "$(gh pr view "${pr}" --json autoMergeRequest --jq '.autoMergeRequest != null')" != "true" ]; then
gh pr merge "${pr}" --squash --auto
fi
shell: bash
- name: Check release
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
run: |
fledge:::release_after_cran_built_binaries()
shell: Rscript {0}