Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 50 additions & 17 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,19 @@ jobs:
git tag -a "v$version" -m "Release v$version" -m "$published"
git push origin "v$version"
fi

# A package that moved on its own (angular 1.11.1 next to core 1.11.0) has no
# v<version> tag to stand for it: it gets one named after itself.
own=$(node scripts/own-release-packages.js)
while read -r tag pkg pv; do
[ -n "$tag" ] || continue
if git rev-parse -q --verify "refs/tags/$tag" >/dev/null; then
echo "Tag $tag already exists - leaving it alone."
else
git tag -a "$tag" -m "Release $tag"
git push origin "$tag"
fi
done <<< "$own"
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Expand All @@ -174,26 +187,44 @@ jobs:

if gh release view "v$version" >/dev/null 2>&1; then
echo "Release v$version already exists - leaving it alone."
exit 0
else
{
echo 'All five packages ship at this version with npm provenance:'
echo
for pkg in core react vue angular svelte; do
echo "- \`@dynamic-field-kit/$pkg@$(node -p "require('./packages/$pkg/package.json').version")\`"
done
echo
awk -v heading="## $version" \
'$0 == heading { found = 1; next } /^## / { if (found) exit } found' \
packages/core/CHANGELOG.md
} > "$RUNNER_TEMP/release-notes.md"

gh release create "v$version" \
--title "v$version" \
--notes-file "$RUNNER_TEMP/release-notes.md" \
--verify-tag \
--latest
fi

{
echo 'All five packages ship at this version with npm provenance:'
echo
for pkg in core react vue angular svelte; do
echo "- \`@dynamic-field-kit/$pkg@$(node -p "require('./packages/$pkg/package.json').version")\`"
done
echo
awk -v heading="## $version" \
# A package that moved on its own gets a Release of its own, from its own
# CHANGELOG. It is not marked latest: v<version> stays the release people land on.
own=$(node scripts/own-release-packages.js)
while read -r tag pkg pv; do
[ -n "$tag" ] || continue
if gh release view "$tag" >/dev/null 2>&1; then
echo "Release $tag already exists - leaving it alone."
continue
fi
awk -v heading="## $pv" \
'$0 == heading { found = 1; next } /^## / { if (found) exit } found' \
packages/core/CHANGELOG.md
} > "$RUNNER_TEMP/release-notes.md"

gh release create "v$version" \
--title "v$version" \
--notes-file "$RUNNER_TEMP/release-notes.md" \
--verify-tag \
--latest
"packages/$pkg/CHANGELOG.md" > "$RUNNER_TEMP/release-notes-$pkg.md"
gh release create "$tag" \
--title "$tag" \
--notes-file "$RUNNER_TEMP/release-notes-$pkg.md" \
--verify-tag \
--latest=false
done <<< "$own"
env:
GH_TOKEN: ${{ github.token }}

Expand All @@ -202,4 +233,6 @@ jobs:
run: |
echo 'Dry run - nothing was committed, tagged or published.'
echo 'Versions that would have shipped are listed above.'
echo 'Packages that would get a tag and a Release of their own (tag, package, version):'
node scripts/own-release-packages.js
git --no-pager diff --stat
64 changes: 64 additions & 0 deletions scripts/own-release-packages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env node
/**
* Lists the packages that need a git tag and a GitHub Release of their own.
*
* A release is tagged `v<version>` after core: the five packages share one version
* line and core anchors it. The `linked` group still lets one package move on its
* own, as angular did in 1.11.1 while core stayed at 1.11.0. That version has no
* `v<version>` tag to stand for it, and release.yml made neither a tag nor a Release
* for it (both were made by hand). Such a package gets
* `@dynamic-field-kit/<pkg>@<version>`, the name changesets gives a package tag.
*
* A package that is behind core at a version an older `v<version>` already covers
* needs nothing.
*
* Prints one line per package: `<tag> <package> <version>`.
*/
const { execFileSync } = require('child_process');
const fs = require('fs');
const path = require('path');

const PACKAGES = ['react', 'vue', 'angular', 'svelte'];

/**
* @param {Record<string, string>} versions package name -> version, core included
* @param {(tag: string) => boolean} tagExists
*/
function ownReleasePackages(versions, tagExists) {
return PACKAGES.filter(
(pkg) => versions[pkg] !== versions.core && !tagExists(`v${versions[pkg]}`),
).map((pkg) => ({
tag: `@dynamic-field-kit/${pkg}@${versions[pkg]}`,
pkg,
version: versions[pkg],
}));
}

function readVersions(root) {
const versions = {};
for (const pkg of ['core', ...PACKAGES]) {
const manifest = path.join(root, 'packages', pkg, 'package.json');
versions[pkg] = JSON.parse(fs.readFileSync(manifest, 'utf8')).version;
}
return versions;
}

function gitTagExists(tag) {
try {
execFileSync('git', ['rev-parse', '-q', '--verify', `refs/tags/${tag}`], {
stdio: 'ignore',
});
return true;
} catch {
return false;
}
}

if (require.main === module) {
const own = ownReleasePackages(readVersions(process.cwd()), gitTagExists);
for (const { tag, pkg, version } of own) {
console.log(`${tag} ${pkg} ${version}`);
}
}

module.exports = { ownReleasePackages, readVersions, PACKAGES };
57 changes: 57 additions & 0 deletions scripts/own-release-packages.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { describe, expect, it } from 'vitest';

import { ownReleasePackages } from './own-release-packages.js';

const line = (version, overrides = {}) => ({
core: version,
react: version,
vue: version,
angular: version,
svelte: version,
...overrides,
});
const tags =
(...names) =>
(tag) =>
names.includes(tag);

describe('ownReleasePackages', () => {
it('lists nothing when every package is on core version', () => {
expect(ownReleasePackages(line('1.12.0'), tags())).toEqual([]);
});

it('lists a package that moved on its own, as angular did in 1.11.1', () => {
expect(
ownReleasePackages(
line('1.11.0', { angular: '1.11.1' }),
tags('v1.11.0'),
),
).toEqual([
{
tag: '@dynamic-field-kit/angular@1.11.1',
pkg: 'angular',
version: '1.11.1',
},
]);
});

it('leaves out a package behind core whose version an older release tag covers', () => {
expect(
ownReleasePackages(
line('1.12.0', { react: '1.11.0' }),
tags('v1.11.0', 'v1.12.0'),
),
).toEqual([]);
});

it('lists every package that moved on its own', () => {
const own = ownReleasePackages(
line('1.11.0', { vue: '1.11.1', svelte: '1.11.2' }),
tags('v1.11.0'),
);
expect(own.map(({ tag }) => tag)).toEqual([
'@dynamic-field-kit/vue@1.11.1',
'@dynamic-field-kit/svelte@1.11.2',
]);
});
});
Loading