Repository navigation
142 lines (136 loc) · 7.54 KB
/
Copy pathphp-plugins-split.yml
File metadata and controls
142 lines (136 loc) · 7.54 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
# A release tag -> the Drupal module (packages/php/drupal) pushed to its
# drupal.org repository, and the Craft plugin (packages/php/craft) to its own
# read-only GitHub repository, each with the tag (see "Distribution" in
# packages/php/DESIGN.md). drupal.org builds a module's releases from tags in
# its own GitLab, and the Craft Plugin Store and Packagist read a plugin's
# composer.json from a repository's root, so neither can be published from
# this monorepo directly. The split is `git subtree split`, as for the
# library (php-split.yml), so each push fast-forwards. Can also be started by
# hand for a tag.
#
# Each half stays off until its repository variable is "true". Needs:
# DRUPAL_SPLIT_ENABLED "true" to push the module
# DRUPAL_SPLIT_REPOSITORY the drupal.org repository's SSH URL
# (git@git.drupal.org:project/cronwatch.git)
# DRUPAL_SPLIT_SSH_KEY secret of the drupal-split environment (deployments
# limited to v* tags and main), the private half of an
# SSH key with push access to it
# CRAFT_SPLIT_ENABLED "true" to push the plugin
# CRAFT_SPLIT_REPOSITORY the plugin's GitHub repository as owner/name
# (cronwatchdev/cronwatch-craft)
# CRAFT_SPLIT_DEPLOY_KEY secret of the craft-split environment (deployments
# limited to v* tags and main), the private half of a
# deploy key with write access to it
name: PHP plugins split
on:
push:
tags: ["v*"]
workflow_dispatch:
inputs:
tag:
description: The release tag to push (v0.6.0, say)
required: true
# The jobs read the monorepo and push elsewhere with their own keys.
permissions:
contents: read
concurrency:
group: php-plugins-split
cancel-in-progress: false
jobs:
# CI must pass on the tagged commit first (ci-passed.yml).
ci:
if: >-
(vars.DRUPAL_SPLIT_ENABLED == 'true' && vars.DRUPAL_SPLIT_REPOSITORY != '') ||
(vars.CRAFT_SPLIT_ENABLED == 'true' && vars.CRAFT_SPLIT_REPOSITORY != '')
uses: ./.github/workflows/ci-passed.yml
permissions:
actions: read
contents: read
with:
tag: ${{ inputs.tag }}
drupal:
needs: ci
if: vars.DRUPAL_SPLIT_ENABLED == 'true' && vars.DRUPAL_SPLIT_REPOSITORY != ''
# Environment secrets: a workflow pushed to another branch cannot read the key.
environment: drupal-split
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
ref: ${{ needs.ci.outputs.sha }}
persist-credentials: false
- name: Split packages/php/drupal and push it with the tag
env:
TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}
REPOSITORY: ${{ vars.DRUPAL_SPLIT_REPOSITORY }}
SSH_KEY: ${{ secrets.DRUPAL_SPLIT_SSH_KEY }}
run: |
case "$TAG" in v[0-9]*) ;; *) echo "not a release tag: $TAG"; exit 1 ;; esac
if [ -z "$SSH_KEY" ]; then echo "DRUPAL_SPLIT_SSH_KEY is not set"; exit 1; fi
version="${TAG#v}"
# The module requires the library of its own release.
required="$(sed -n 's/^ "cronwatch\/cronwatch": "\^\(.*\)"$/\1/p' packages/php/drupal/composer.json)"
if [ "$required" != "$version" ]; then echo "packages/php/drupal requires cronwatch/cronwatch ^$required, the tag is $TAG"; exit 1; fi
# drupal.org names releases X.Y.Z (no "v") and their branches X.Y.x.
branch="$(echo "$version" | cut -d. -f1-2).x"
key="$RUNNER_TEMP/split_key"
printf '%s\n' "$SSH_KEY" > "$key"
chmod 600 "$key"
# git.drupal.org's ED25519 host key, checked against the fingerprint drupal.org
# publishes (SHA256:dPC6RYiFfvVB/epk5s/lisF4jCbOFJnitbYPy6Dsog8, at
# https://git.drupalcode.org/help/instance_configuration), pinned rather than trusted on first use.
printf '%s\n' 'git.drupal.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKCkFTXM7BUQUHlDkVmQV6qNkIeSIRBTNzlLn+T/APHa' > "$RUNNER_TEMP/known_hosts"
export GIT_SSH_COMMAND="ssh -i $key -o IdentitiesOnly=yes -o UserKnownHostsFile=$RUNNER_TEMP/known_hosts"
git config user.name "CronWatch release"
git config user.email "noreply@cronwatch.dev"
split="$(git subtree split --prefix=packages/php/drupal HEAD)"
git tag -f -a "$version" -m "Release $version" "$split"
git push "$REPOSITORY" "$split:refs/heads/$branch"
# A tag already there on this commit is a rerun; on another commit, a release changed after it shipped.
remote_tag="$(git ls-remote "$REPOSITORY" "refs/tags/$version^{}" | cut -f1)"
if [ -z "$remote_tag" ]; then git push "$REPOSITORY" "refs/tags/$version";
elif [ "$remote_tag" = "$split" ]; then echo "$version is already there on this commit";
else echo "$version is already there on another commit ($remote_tag)"; exit 1; fi
rm -f "$key"
craft:
needs: ci
if: vars.CRAFT_SPLIT_ENABLED == 'true' && vars.CRAFT_SPLIT_REPOSITORY != ''
environment: craft-split
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
ref: ${{ needs.ci.outputs.sha }}
persist-credentials: false
- name: Split packages/php/craft and push it with the tag
env:
TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}
REPOSITORY: ${{ vars.CRAFT_SPLIT_REPOSITORY }}
DEPLOY_KEY: ${{ secrets.CRAFT_SPLIT_DEPLOY_KEY }}
run: |
case "$TAG" in v[0-9]*) ;; *) echo "not a release tag: $TAG"; exit 1 ;; esac
if [ -z "$DEPLOY_KEY" ]; then echo "CRAFT_SPLIT_DEPLOY_KEY is not set"; exit 1; fi
required="$(sed -n 's/^ "cronwatch\/cronwatch": "\^\(.*\)"$/\1/p' packages/php/craft/composer.json)"
if [ "v$required" != "$TAG" ]; then echo "packages/php/craft requires cronwatch/cronwatch ^$required, the tag is $TAG"; exit 1; fi
key="$RUNNER_TEMP/split_key"
printf '%s\n' "$DEPLOY_KEY" > "$key"
chmod 600 "$key"
# GitHub's published ED25519 host key (SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU,
# from https://api.github.com/meta), pinned rather than trusted on first use.
printf '%s\n' 'github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl' > "$RUNNER_TEMP/known_hosts"
export GIT_SSH_COMMAND="ssh -i $key -o IdentitiesOnly=yes -o UserKnownHostsFile=$RUNNER_TEMP/known_hosts"
git config user.name "CronWatch release"
git config user.email "noreply@cronwatch.dev"
split="$(git subtree split --prefix=packages/php/craft HEAD)"
git tag -f -a "$TAG" -m "Release ${TAG#v}" "$split"
git push "git@github.com:$REPOSITORY.git" "$split:refs/heads/main"
# A tag already there on this commit is a rerun; on another commit, a release changed after it shipped.
remote_tag="$(git ls-remote "git@github.com:$REPOSITORY.git" "refs/tags/$TAG^{}" | cut -f1)"
if [ -z "$remote_tag" ]; then git push "git@github.com:$REPOSITORY.git" "refs/tags/$TAG";
elif [ "$remote_tag" = "$split" ]; then echo "$TAG is already there on this commit";
else echo "$TAG is already there on another commit ($remote_tag)"; exit 1; fi
rm -f "$key"