Skip to content

Commit fa7d3c8

Browse files
authored
feat(cli/action): publish multiple module entries (#247)
1 parent 1050686 commit fa7d3c8

File tree

15 files changed

+532
-228
lines changed

15 files changed

+532
-228
lines changed

.github/workflows/action-e2e.yaml

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ jobs:
4444
run: |
4545
set -o errexit -o nounset -o pipefail -o xtrace
4646
47-
if [[ "${{ steps.create_entry.outputs.module-name }}" != "versioned" ]]; then
48-
echo "Expected output module-name to be 'versioned' but it was '${{ steps.create_entry.outputs.module-name }}'"
47+
if [[ "${{ steps.create_entry.outputs.module-names }}" != "versioned" ]]; then
48+
echo "Expected output module-names to be 'versioned' but it was '${{ steps.create_entry.outputs.module-name }}'"
4949
exit 1
5050
fi
5151
test-github-repository-default:
@@ -105,3 +105,38 @@ jobs:
105105
106106
[ -f attestations/MODULE.bazel.intoto.jsonl ]
107107
[ -f attestations/source.json.intoto.jsonl ]
108+
test-multi-module-attestations:
109+
# Test that attestation files are given a prefixed name when multiple modules are published
110+
runs-on: ubuntu-latest
111+
permissions:
112+
id-token: write
113+
attestations: write
114+
steps:
115+
- uses: actions/checkout@v2
116+
with:
117+
path: this
118+
- name: Setup test fixture
119+
run: this/e2e/action/setup-test-fixture.sh multi-module multi-module-1.0.0
120+
- name: Create registry
121+
run: |
122+
mkdir -p bazel-central-registry/modules
123+
cd bazel-central-registry
124+
git init
125+
- name: Create entry
126+
uses: ./this
127+
with:
128+
attest: true
129+
attestations-dest: attestations
130+
tag: v1.0.0
131+
module-version: 1.0.0
132+
github-repository: testorg/multi-module
133+
templates-dir: this/e2e/fixtures/multi-module/.bcr
134+
local-registry: bazel-central-registry
135+
- name: Test attestations exist
136+
run: |-
137+
set -o errexit -o nounset -o pipefail -o xtrace
138+
139+
[ -f attestations/module.MODULE.bazel.intoto.jsonl ]
140+
[ -f attestations/module.source.json.intoto.jsonl ]
141+
[ -f attestations/submodule.MODULE.bazel.intoto.jsonl ]
142+
[ -f attestations/submodule.source.json.intoto.jsonl ]

dist/action/index.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/cli/index.js

Lines changed: 230 additions & 90 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

e2e/action/setup-test-fixture.sh

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,20 @@ STRIP_PREFIX="${2}"
66

77
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
88
ACTION_REPO_PATH="${SCRIPT_DIR}/../../"
9+
FIXTURE_PATH="${ACTION_REPO_PATH}/e2e/fixtures/${FIXTURE}"
910

1011
# Create a release archive from a fixture
11-
tar -czvf archive.tar.gz -C "${ACTION_REPO_PATH}/e2e/fixtures/${FIXTURE}" --transform "s,^./,${STRIP_PREFIX}/," --sort=name --owner=root:0 --group=root:0 --mtime="UTC 1980-02-01" .
12+
tar -czvf archive.tar.gz -C "${FIXTURE_PATH}" --transform "s,^./,${STRIP_PREFIX}/," --sort=name --owner=root:0 --group=root:0 --mtime="UTC 1980-02-01" .
13+
14+
if [ -f "${FIXTURE_PATH}/.bcr/config.yml" ]; then
15+
readarray -t MODULE_ROOTS < <(cat "${FIXTURE_PATH}/.bcr/config.yml" | yq -r '.moduleRoots.[]')
16+
else
17+
MODULE_ROOTS=(".")
18+
fi
1219

1320
# Substitute the archive url to a local file path
14-
cat "${ACTION_REPO_PATH}/e2e/fixtures/${FIXTURE}/.bcr/source.template.json" | jq ".url = \"file://$(realpath archive.tar.gz)\"" > "/tmp/source.template.json"
15-
mv /tmp/source.template.json "${ACTION_REPO_PATH}/e2e/fixtures/${FIXTURE}/.bcr/source.template.json"
16-
cat "${ACTION_REPO_PATH}/e2e/fixtures/${FIXTURE}/.bcr/source.template.json"
21+
for MODULE_ROOT in "${MODULE_ROOTS[@]}"; do
22+
cat "${FIXTURE_PATH}/.bcr/${MODULE_ROOT}/source.template.json" | jq ".url = \"file://$(realpath archive.tar.gz)\"" > "/tmp/source.template.json"
23+
mv /tmp/source.template.json "${FIXTURE_PATH}/.bcr/${MODULE_ROOT}/source.template.json"
24+
cat "${FIXTURE_PATH}/.bcr/${MODULE_ROOT}/source.template.json"
25+
done

e2e/cli/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ bats_test(
99
data = [
1010
"//e2e/fixtures",
1111
"//e2e/fixtures:attestations",
12+
"//e2e/fixtures:multi-module",
1213
"//e2e/fixtures:versioned",
1314
"//e2e/fixtures:zip",
1415
"//src/application/cli:bundle",

e2e/cli/e2e.bats

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,35 @@ mock_attestation() {
100100
assert_file_exists "${ENTRY_PATH}/1.0.0/presubmit.yml"
101101
}
102102

103+
@test 'multi-module entry' {
104+
FIXTURE="e2e/fixtures/multi-module"
105+
cp -R "${FIXTURE}" "${TEST_TMPDIR}/"
106+
FIXTURE="${TEST_TMPDIR}/$(basename "${FIXTURE}")"
107+
TEMPLATES_DIR="${FIXTURE}/.bcr"
108+
RELEASE_ARCHIVE="e2e/fixtures/multi-module-multi-module-1.0.0.tar.gz"
109+
110+
swap_source_url "${TEMPLATES_DIR}/source.template.json" "file://$(realpath "${RELEASE_ARCHIVE}")"
111+
swap_source_url "${TEMPLATES_DIR}/submodule/source.template.json" "file://$(realpath "${RELEASE_ARCHIVE}")"
112+
113+
run "${NODE_BIN}" "${CLI_BIN}" create-entry --local-registry "${REGISTRY_PATH}" --templates-dir "${TEMPLATES_DIR}" --module-version 1.0.0 --github-repository testorg/multi-module --tag v1.0.0
114+
115+
assert_success
116+
117+
ENTRY_PATH="${REGISTRY_PATH}/modules/module"
118+
119+
assert_file_exists "${ENTRY_PATH}/metadata.json"
120+
assert_file_exists "${ENTRY_PATH}/1.0.0/MODULE.bazel"
121+
assert_file_exists "${ENTRY_PATH}/1.0.0/source.json"
122+
assert_file_exists "${ENTRY_PATH}/1.0.0/presubmit.yml"
123+
124+
ENTRY_PATH="${REGISTRY_PATH}/modules/submodule"
125+
126+
assert_file_exists "${ENTRY_PATH}/metadata.json"
127+
assert_file_exists "${ENTRY_PATH}/1.0.0/MODULE.bazel"
128+
assert_file_exists "${ENTRY_PATH}/1.0.0/source.json"
129+
assert_file_exists "${ENTRY_PATH}/1.0.0/presubmit.yml"
130+
}
131+
103132
@test 'create entry with attestations' {
104133
FIXTURE="e2e/fixtures/attestations"
105134
cp -R "${FIXTURE}" "${TEST_TMPDIR}/"
@@ -154,7 +183,7 @@ mock_attestation() {
154183
ENTRY_PATH="${REGISTRY_PATH}/modules/versioned/1.0.0"
155184

156185
ACTUAL=$("${jq}" <<< ${STDOUT} .)
157-
EXPECTED=$("${jq}" --null-input "{moduleName: \"versioned\", entryPath: \"${ENTRY_PATH}\"}")
186+
EXPECTED=$("${jq}" --null-input "{\"modules\": [{\"name\": \"versioned\", entryPath: \"${ENTRY_PATH}\"}]}")
158187

159188
assert_equal "${EXPECTED}" "${ACTUAL}"
160189
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Ruleset repo that has multiple `moduleRoots` configured.
1+
Ruleset repo that has multiple `moduleRoots` configured and a shared release archive.

e2e/github-webhook/__snapshots__/e2e.spec.js.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ bcr_test_module:
169169
modules/module/1.0.0/source.json
170170
----------------------------------------------------
171171
{
172-
"integrity": "sha256-GIERNCByLpef3PWA31F/50ECIeCXV3jcieI/pv1uovg=",
172+
"integrity": "sha256-futnmCx8nl4tIw5yGYoH71w4K3fUet2eXjb/ek4cIKU=",
173173
"strip_prefix": "multi-module-1.0.0",
174174
"url": "https://github.com/testorg/multi-module/releases/download/v1.0.0.tar.gz"
175175
}
@@ -223,7 +223,7 @@ bcr_test_module:
223223
modules/submodule/1.0.0/source.json
224224
----------------------------------------------------
225225
{
226-
"integrity": "sha256-GIERNCByLpef3PWA31F/50ECIeCXV3jcieI/pv1uovg=",
226+
"integrity": "sha256-futnmCx8nl4tIw5yGYoH71w4K3fUet2eXjb/ek4cIKU=",
227227
"strip_prefix": "multi-module-1.0.0/submodule",
228228
"url": "https://github.com/testorg/multi-module/releases/download/v1.0.0.tar.gz"
229229
}

src/application/action/attest.ts

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,23 @@ export async function attest(
1818
if (!inputs.ghToken) {
1919
throw new Error('gh-token must be set to produce attestations');
2020
}
21-
await attestEntryFiles(
22-
cliOutput.entryPath,
23-
inputs.attestationsDest,
24-
inputs.ghToken
25-
);
21+
22+
for (const module of cliOutput.modules) {
23+
await attestEntryFiles(
24+
module.entryPath,
25+
inputs.attestationsDest,
26+
inputs.ghToken,
27+
cliOutput.modules.length > 1 ? module.name : null
28+
);
29+
}
2630
}
2731
}
2832

2933
async function attestEntryFiles(
3034
entryPath: string,
3135
attestationsDest: string,
32-
ghToken: string
36+
ghToken: string,
37+
prefix: string | null
3338
) {
3439
if (!fs.existsSync(attestationsDest)) {
3540
fs.mkdirSync(attestationsDest, { recursive: true });
@@ -39,7 +44,10 @@ async function attestEntryFiles(
3944
await attestArtifact(
4045
artifact,
4146
path.join(entryPath, artifact),
42-
attestationsDest,
47+
path.join(
48+
attestationsDest,
49+
`${prefix !== null ? `${prefix}.` : ''}${artifact}.intoto.jsonl`
50+
),
4351
ghToken
4452
);
4553
}
@@ -69,9 +77,5 @@ async function attestArtifact(
6977
token: ghToken,
7078
});
7179

72-
fs.writeFileSync(
73-
path.join(dest, `${artifactName}.intoto.jsonl`),
74-
JSON.stringify(attestation.bundle),
75-
'utf-8'
76-
);
80+
fs.writeFileSync(dest, JSON.stringify(attestation.bundle), 'utf-8');
7781
}

src/application/action/main.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,10 @@ async function main() {
6767
return;
6868
}
6969

70-
core.setOutput('module-name', cliOutput.moduleName);
70+
core.setOutput(
71+
'module-names',
72+
cliOutput.modules.map((m) => m.name).join(',')
73+
);
7174

7275
await attest(inputs, cliOutput!);
7376
} catch (error) {

0 commit comments

Comments
 (0)