feat: publish the exact @ekklesia package train to the npm registry (ADR 0053) #81
@@ -165,12 +165,12 @@ jobs:
|
||||
# packages, and verifies. Nothing is published and no credential exists here. A future publish
|
||||
# job must depend on this job and publish only the artifacts it proved.
|
||||
- name: Build, reproduce, and consume the public package train
|
||||
run: pnpm test:package-release --keep .package-release
|
||||
run: pnpm test:package-release --keep package-train
|
||||
|
||||
- name: Describe the proven release train
|
||||
id: release
|
||||
run: |
|
||||
release="$(find .package-release -mindepth 1 -maxdepth 1 -type d)"
|
||||
release="$(find package-train -mindepth 1 -maxdepth 1 -type d)"
|
||||
manifest="$release/ekklesia-package-train.json"
|
||||
{
|
||||
echo "version=$(node -p 'JSON.parse(require("fs").readFileSync(process.argv[1], "utf8")).version' "$manifest")"
|
||||
@@ -179,14 +179,15 @@ jobs:
|
||||
} >>"$GITHUB_OUTPUT"
|
||||
cat "$manifest"
|
||||
|
||||
# The exact release artifacts, for the jobs that consume them. Version 3 of the artifact
|
||||
# The exact release artifacts, for the jobs that consume them, from a directory whose name does
|
||||
# not start with a dot: the artifact actions leave hidden files out. Version 3 of the artifact
|
||||
# actions: version 4 refuses any server that is not github.com, which this Gitea is not, while
|
||||
# Gitea implements the protocol version 3 uses. A consumer checks the files, not the wrapper.
|
||||
- name: Hand the release train on
|
||||
uses: actions/upload-artifact@c6a3b2bd78b3985e4b2f15397fec357f0fd808de # v3.2.2-node20
|
||||
with:
|
||||
name: package-train
|
||||
path: .package-release/
|
||||
path: package-train/
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
@@ -228,13 +229,13 @@ jobs:
|
||||
uses: actions/download-artifact@ad191675b41f6a5b46da9a048cb6893812da158b # v3.1.0-node20
|
||||
with:
|
||||
name: package-train
|
||||
path: .package-release/
|
||||
path: package-train/
|
||||
|
||||
- name: Check it is exactly that train
|
||||
env:
|
||||
EXPECTED_MANIFEST_SHA256: ${{ needs.package-release.outputs.manifest_sha256 }}
|
||||
run: |
|
||||
release="$(find .package-release -mindepth 1 -maxdepth 1 -type d)"
|
||||
release="$(find package-train -mindepth 1 -maxdepth 1 -type d)"
|
||||
actual="$(sha256sum "$release/ekklesia-package-train.json" | cut -d' ' -f1)"
|
||||
if [[ -z "$EXPECTED_MANIFEST_SHA256" || "$actual" != "$EXPECTED_MANIFEST_SHA256" ]]; then
|
||||
echo "The received release manifest is not the one the package-release job proved." >&2
|
||||
@@ -243,7 +244,7 @@ jobs:
|
||||
(cd "$release" && sha256sum --check --strict SHA256SUMS)
|
||||
|
||||
- name: Publish it to a disposable Gitea, and prove the round trip and recovery
|
||||
run: bash scripts/test-package-publication.sh --release "$(find .package-release -mindepth 1 -maxdepth 1 -type d)"
|
||||
run: bash scripts/test-package-publication.sh --release "$(find package-train -mindepth 1 -maxdepth 1 -type d)"
|
||||
|
||||
# Whatever happened above, this job's own stacks do not outlive it.
|
||||
- name: Remove this job's CI stacks
|
||||
|
||||
@@ -59,12 +59,12 @@ jobs:
|
||||
|
||||
# The same credential-free gate as CI: build, reproduce, and consume the train.
|
||||
- name: Build, reproduce, and consume the public package train
|
||||
run: pnpm test:package-release --keep .package-release
|
||||
run: pnpm test:package-release --keep package-train
|
||||
|
||||
- name: Describe the proven release train
|
||||
id: release
|
||||
run: |
|
||||
release="$(find .package-release -mindepth 1 -maxdepth 1 -type d)"
|
||||
release="$(find package-train -mindepth 1 -maxdepth 1 -type d)"
|
||||
manifest="$release/ekklesia-package-train.json"
|
||||
{
|
||||
echo "version=$(node -p 'JSON.parse(require("fs").readFileSync(process.argv[1], "utf8")).version' "$manifest")"
|
||||
@@ -72,12 +72,13 @@ jobs:
|
||||
echo "manifest_sha256=$(sha256sum "$manifest" | cut -d' ' -f1)"
|
||||
} >>"$GITHUB_OUTPUT"
|
||||
|
||||
# Artifact actions version 3: version 4 refuses any server that is not github.com.
|
||||
# Artifact actions version 3: version 4 refuses any server that is not github.com. The directory
|
||||
# name must not start with a dot: the artifact actions leave hidden files out.
|
||||
- name: Hand the release train on
|
||||
uses: actions/upload-artifact@c6a3b2bd78b3985e4b2f15397fec357f0fd808de # v3.2.2-node20
|
||||
with:
|
||||
name: package-train
|
||||
path: .package-release/
|
||||
path: package-train/
|
||||
if-no-files-found: error
|
||||
retention-days: 90
|
||||
|
||||
@@ -102,7 +103,7 @@ jobs:
|
||||
uses: actions/download-artifact@ad191675b41f6a5b46da9a048cb6893812da158b # v3.1.0-node20
|
||||
with:
|
||||
name: package-train
|
||||
path: .package-release/
|
||||
path: package-train/
|
||||
|
||||
# The tool validates the whole train against its manifest, that manifest against the gate's,
|
||||
# its version against the request, and its revision against this commit, before it sends
|
||||
@@ -115,7 +116,7 @@ jobs:
|
||||
MANIFEST_SHA256: ${{ needs.package-release.outputs.manifest_sha256 }}
|
||||
run: |
|
||||
node scripts/publish-package-train.ts \
|
||||
--release "$(find .package-release -mindepth 1 -maxdepth 1 -type d)" \
|
||||
--release "$(find package-train -mindepth 1 -maxdepth 1 -type d)" \
|
||||
--registry "$EKKLESIA_PACKAGES_REGISTRY" \
|
||||
--version "$TRAIN_VERSION" \
|
||||
--revision "$TRAIN_REVISION" \
|
||||
|
||||
@@ -26,3 +26,5 @@ packages/module-pack/.fixtures/
|
||||
|
||||
# `pnpm packages:release` writes package release trains here (scripts/package-release.ts).
|
||||
.package-release/
|
||||
# CI keeps the proven release here to hand it on as a workflow artifact (scripts/test-package-release.sh --keep).
|
||||
/package-train/
|
||||
|
||||
@@ -531,12 +531,16 @@ describe("when the real registry can be written to", () => {
|
||||
expect(publishRuns).not.toMatch(/pnpm|npm (?:install|ci|run|pack)|package-release\.ts/u);
|
||||
});
|
||||
|
||||
it("uses the artifact actions that work on this Gitea, pinned by commit", async () => {
|
||||
it("uses the artifact actions that work on this Gitea, pinned by commit, on visible paths", async () => {
|
||||
for (const file of ["ci.yml", "publish-packages.yml"]) {
|
||||
const text = await readFile(path.join(repositoryRoot, ".github/workflows", file), "utf8");
|
||||
for (const use of text.matchAll(/uses: (actions\/(?:up|down)load-artifact)@(\S+)/gu)) {
|
||||
expect(use[2], `${file} ${use[1]}`).toMatch(/^[0-9a-f]{40}$/u);
|
||||
}
|
||||
// The artifact actions leave hidden files out: a path starting with a dot uploads nothing.
|
||||
for (const artifactPath of text.matchAll(/^\s+path: (\S+)$/gmu)) {
|
||||
expect(artifactPath[1], file).not.toMatch(/^\.|\/\./u);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user