@firestartr/cli 2.7.0-snapshot-17 → 2.7.0-snapshot-19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.js +220 -53
- package/build/packages/gh_provisioner/src/entities/ghfeature/helpers/index.d.ts +2 -1
- package/build/packages/gh_provisioner/src/entities/ghfeature/helpers/managed_files.d.ts +14 -1
- package/build/packages/gh_provisioner/src/entities/ghfeature/index.d.ts +31 -1
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -290172,7 +290172,7 @@ async function renderClaim(catalogScope, firestartrScope, claim, patches, previo
|
|
|
290172
290172
|
.map((segment) => encodeURIComponent(segment))
|
|
290173
290173
|
.join('/');
|
|
290174
290174
|
apiAnnotations['backstage.io/edit-url'] =
|
|
290175
|
-
`${repoUrl}/blob/${
|
|
290175
|
+
`${repoUrl}/blob/${getDefaultBranch()}/${relativePath}`;
|
|
290176
290176
|
}
|
|
290177
290177
|
const apiChart = new charts.CatalogApiChart(catalogScope, `${chartId}-api-${sanitizedApiName}`, firestartrId, {
|
|
290178
290178
|
name: sanitizedApiName,
|
|
@@ -298747,16 +298747,16 @@ async function TFCheckRun(cmd, item) {
|
|
|
298747
298747
|
checkRun.mdOptionsDetails({
|
|
298748
298748
|
quotes: 'terraform',
|
|
298749
298749
|
});
|
|
298750
|
-
checkRun.update('Initiating', 'queued');
|
|
298750
|
+
void checkRun.update('Initiating', 'queued');
|
|
298751
298751
|
return {
|
|
298752
298752
|
fnData: (d) => {
|
|
298753
|
-
checkRun.update(d.toString(), 'in_progress');
|
|
298753
|
+
void checkRun.update(d.toString(), 'in_progress');
|
|
298754
298754
|
},
|
|
298755
298755
|
fnEnd: () => {
|
|
298756
|
-
checkRun.close('OK', true);
|
|
298756
|
+
void checkRun.close('OK', true);
|
|
298757
298757
|
},
|
|
298758
298758
|
fnOnError: (_) => {
|
|
298759
|
-
checkRun.close('KO', false);
|
|
298759
|
+
void checkRun.close('KO', false);
|
|
298760
298760
|
},
|
|
298761
298761
|
};
|
|
298762
298762
|
}
|
|
@@ -300635,8 +300635,8 @@ const MODULES = {
|
|
|
300635
300635
|
},
|
|
300636
300636
|
FirestartrGithubRepositorySecretsSection: {
|
|
300637
300637
|
module: 'git::https://github.com/prefapp/tfm.git//modules/github-repo-secrets-section',
|
|
300638
|
-
// github-repo-secrets-section-v0.1.
|
|
300639
|
-
ref: '
|
|
300638
|
+
// github-repo-secrets-section-v0.1.2
|
|
300639
|
+
ref: 'c2e983dc57d8f879fd8ec4df048fbb604e4f04b2',
|
|
300640
300640
|
},
|
|
300641
300641
|
FirestartrGithubRepository: {
|
|
300642
300642
|
module: 'git::https://github.com/prefapp/tfm.git//modules/github-repo',
|
|
@@ -300645,8 +300645,8 @@ const MODULES = {
|
|
|
300645
300645
|
},
|
|
300646
300646
|
FirestartrGithubRepositoryFeature: {
|
|
300647
300647
|
module: 'git::https://github.com/prefapp/tfm.git//modules/github-files-set',
|
|
300648
|
-
//
|
|
300649
|
-
ref: '
|
|
300648
|
+
// fix/provision-once-then-untrack
|
|
300649
|
+
ref: 'fix/provision-once-then-untrack',
|
|
300650
300650
|
},
|
|
300651
300651
|
FirestartrGithubMembership: {
|
|
300652
300652
|
module: 'git::https://github.com/prefapp/tfm.git//modules/github-membership',
|
|
@@ -300946,10 +300946,14 @@ class EntityGroup extends base_Entity {
|
|
|
300946
300946
|
}
|
|
300947
300947
|
}
|
|
300948
300948
|
|
|
300949
|
+
// EXTERNAL MODULE: external "crypto"
|
|
300950
|
+
var external_crypto_ = __nccwpck_require__(6113);
|
|
300951
|
+
var external_crypto_default = /*#__PURE__*/__nccwpck_require__.n(external_crypto_);
|
|
300949
300952
|
;// CONCATENATED MODULE: ../gh_provisioner/src/entities/ghrepositorysecretssection/secrets.ts
|
|
300950
300953
|
|
|
300951
300954
|
|
|
300952
300955
|
|
|
300956
|
+
|
|
300953
300957
|
async function provisionRepositorySecrets(grss, repo) {
|
|
300954
300958
|
gh_provisioner_src_logger.info(`[gh-provisioner] ${grss.k8sId} provisioning secrets`);
|
|
300955
300959
|
const sections = [
|
|
@@ -300990,14 +300994,21 @@ async function provisionRepositorySecret(grss, section, repoSecretName, secretRe
|
|
|
300990
300994
|
}
|
|
300991
300995
|
async function createEncryptedSecret(grss, secretRef, secretPatcherFunction, section, repoSecretName, repo) {
|
|
300992
300996
|
gh_provisioner_src_logger.info(`[gh-provisioner] generating encrypted secret ${grss.k8sId}/${section}/${repoSecretName}`);
|
|
300993
|
-
const
|
|
300997
|
+
const plainSecret = base_Entity.refResolver(secretRef);
|
|
300998
|
+
const plainTextSecret = plainSecret.getOutput(secretRef.key);
|
|
300999
|
+
const plaintextSha256 = external_crypto_default().createHash('sha256')
|
|
301000
|
+
.update(plainTextSecret)
|
|
301001
|
+
.digest('hex');
|
|
301002
|
+
const { key_id, encrypted_value } = await encryptSecret(grss, plainTextSecret, section, repo);
|
|
300994
301003
|
secretPatcherFunction({
|
|
300995
301004
|
secretName: repoSecretName,
|
|
300996
301005
|
repository: repo.getDepName(),
|
|
300997
301006
|
encryptedValue: encrypted_value,
|
|
300998
|
-
|
|
300999
|
-
|
|
301000
|
-
}
|
|
301007
|
+
});
|
|
301008
|
+
grss.patchData({
|
|
301009
|
+
path: `/config/${section}_sha256/${repoSecretName}`,
|
|
301010
|
+
op: PatchOperations.add,
|
|
301011
|
+
value: plaintextSha256,
|
|
301001
301012
|
});
|
|
301002
301013
|
}
|
|
301003
301014
|
async function createUnencryptedSecret(grss, secretRef, secretPatcherFunction, section, repoSecretName, repo) {
|
|
@@ -301010,9 +301021,7 @@ async function createUnencryptedSecret(grss, secretRef, secretPatcherFunction, s
|
|
|
301010
301021
|
plaintextValue: plainTextSecret,
|
|
301011
301022
|
});
|
|
301012
301023
|
}
|
|
301013
|
-
async function encryptSecret(grss,
|
|
301014
|
-
const plainSecret = base_Entity.refResolver(secretRef);
|
|
301015
|
-
const plainTextSecret = plainSecret.getOutput(secretRef.key);
|
|
301024
|
+
async function encryptSecret(grss, plainTextSecret, section, repo) {
|
|
301016
301025
|
const v = await grss.runWithGithubProvider(async () => {
|
|
301017
301026
|
return await github["default"].encryption.encryptRepoSecret(repo.cr.spec.org, repo.getDepName(), section, plainTextSecret);
|
|
301018
301027
|
});
|
|
@@ -301030,6 +301039,9 @@ class EntityGHRepositorySecretsSection extends base_Entity {
|
|
|
301030
301039
|
actions: {},
|
|
301031
301040
|
codespaces: {},
|
|
301032
301041
|
dependabot: {},
|
|
301042
|
+
actions_sha256: {},
|
|
301043
|
+
codespaces_sha256: {},
|
|
301044
|
+
dependabot_sha256: {},
|
|
301033
301045
|
},
|
|
301034
301046
|
});
|
|
301035
301047
|
}
|
|
@@ -301711,27 +301723,83 @@ class EntityGHRepo extends base_Entity {
|
|
|
301711
301723
|
;// CONCATENATED MODULE: ../gh_provisioner/src/entities/ghfeature/helpers/managed_files.ts
|
|
301712
301724
|
|
|
301713
301725
|
|
|
301726
|
+
/**
|
|
301727
|
+
* Migration reimport path for `import-with-reimport` operations.
|
|
301728
|
+
*
|
|
301729
|
+
* Populates `config.files` with ONLY non-user-managed files so the subsequent
|
|
301730
|
+
* `loadAddressesToImport` can generate correct import blocks for them.
|
|
301731
|
+
* Seeds `installed_managed_files` from ALL `userManaged: true` addresses in the
|
|
301732
|
+
* current CR spec so the TFM input is ready for the next regular apply cycle.
|
|
301733
|
+
*/
|
|
301734
|
+
async function seedForMigrationReiimport(ghFeature) {
|
|
301735
|
+
const cr = ghFeature.cr;
|
|
301736
|
+
const repoInfo = cr.spec.repositoryTarget;
|
|
301737
|
+
// Only non-user-managed files go into TF config during migration reimport.
|
|
301738
|
+
// User-managed files receive no import block (see ADR 0005).
|
|
301739
|
+
for (const file of cr.spec.files) {
|
|
301740
|
+
if (!file.userManaged) {
|
|
301741
|
+
createFileProvision(ghFeature, file);
|
|
301742
|
+
}
|
|
301743
|
+
}
|
|
301744
|
+
// Seed installed_managed_files from ALL userManaged:true addresses in spec.
|
|
301745
|
+
// This ensures the TFM input is populated so the output is computable on the
|
|
301746
|
+
// operator's next regular apply (second cycle of the two-cycle migration).
|
|
301747
|
+
const allUserManagedAddresses = cr.spec.files
|
|
301748
|
+
.filter((f) => f.userManaged)
|
|
301749
|
+
.map((f) => `${f.path}/${f.targetBranch || repoInfo.branch}`);
|
|
301750
|
+
ghFeature.patchData({
|
|
301751
|
+
op: PatchOperations.replace,
|
|
301752
|
+
path: '/installed_managed_files',
|
|
301753
|
+
value: allUserManagedAddresses,
|
|
301754
|
+
});
|
|
301755
|
+
}
|
|
301714
301756
|
async function provisionManagedFiles(ghFeature) {
|
|
301715
301757
|
const cr = ghFeature.cr;
|
|
301716
301758
|
const repoInfo = cr.spec.repositoryTarget;
|
|
301717
301759
|
const repoRef = base_Entity.refResolver(cr.spec.repositoryTarget.ref);
|
|
301760
|
+
// Read the accumulated list of previously provisioned user-managed file addresses
|
|
301761
|
+
// from the entity's output secrets. Defaults to [] on first apply.
|
|
301762
|
+
const selfOutputs = base_Entity.refResolver({ kind: 'self', name: 'outputs' });
|
|
301763
|
+
const rawInstalledFiles = selfOutputs?.getOutput('installed_managed_files');
|
|
301764
|
+
const installedManagedFiles = Array.isArray(rawInstalledFiles)
|
|
301765
|
+
? rawInstalledFiles
|
|
301766
|
+
: [];
|
|
301767
|
+
const newlyProvisionedAddresses = [];
|
|
301718
301768
|
for (const file of cr.spec.files) {
|
|
301769
|
+
const branch = file.targetBranch || repoInfo.branch;
|
|
301770
|
+
const address = `${file.path}/${branch}`;
|
|
301719
301771
|
if (file.userManaged) {
|
|
301772
|
+
if (installedManagedFiles.includes(address)) {
|
|
301773
|
+
// Already provisioned — skip from TF config entirely so Terraform
|
|
301774
|
+
// never overwrites or deletes user edits.
|
|
301775
|
+
continue;
|
|
301776
|
+
}
|
|
301777
|
+
// New user-managed file — provision once. Fetch existing content from
|
|
301778
|
+
// the repo if available so the seed commit preserves the current state.
|
|
301779
|
+
newlyProvisionedAddresses.push(address);
|
|
301720
301780
|
try {
|
|
301721
301781
|
const content = await ghFeature.getFileContentFromProvider(cr.spec.org, `/${cr.spec.org}/${repoRef.getDepName()}/${repoInfo.branch}/${file.path}`);
|
|
301722
|
-
|
|
301723
|
-
file.content = newContent;
|
|
301782
|
+
file.content = Buffer.from(content, 'binary').toString('base64');
|
|
301724
301783
|
}
|
|
301725
301784
|
catch (e) {
|
|
301726
|
-
gh_provisioner_src_logger.error(`File ${file.path} not found in repo ${repoInfo.ref
|
|
301785
|
+
gh_provisioner_src_logger.error(`File ${file.path} not found in repo ${repoInfo.ref?.name} on branch ${repoInfo.branch}. File content not updated`);
|
|
301727
301786
|
}
|
|
301787
|
+
createFileProvision(ghFeature, file);
|
|
301788
|
+
}
|
|
301789
|
+
else {
|
|
301790
|
+
// Non-user-managed — add to TF config normally (Terraform manages content).
|
|
301791
|
+
createFileProvision(ghFeature, file);
|
|
301728
301792
|
}
|
|
301729
301793
|
}
|
|
301730
|
-
//
|
|
301731
|
-
//
|
|
301732
|
-
|
|
301733
|
-
|
|
301734
|
-
|
|
301794
|
+
// Write the updated accumulated address list back into the document as a
|
|
301795
|
+
// top-level TFM input. The TFM output will grow this list monotonically
|
|
301796
|
+
// and subtract any files that transition away from userManaged.
|
|
301797
|
+
ghFeature.patchData({
|
|
301798
|
+
op: PatchOperations.replace,
|
|
301799
|
+
path: '/installed_managed_files',
|
|
301800
|
+
value: [...installedManagedFiles, ...newlyProvisionedAddresses],
|
|
301801
|
+
});
|
|
301802
|
+
return { newlyProvisionedAddresses, installedManagedFiles };
|
|
301735
301803
|
}
|
|
301736
301804
|
function createFileProvision(ghFeature, file) {
|
|
301737
301805
|
const cr = ghFeature.cr;
|
|
@@ -302005,7 +302073,9 @@ class EntityGHFeature extends base_Entity {
|
|
|
302005
302073
|
config: {
|
|
302006
302074
|
files: [],
|
|
302007
302075
|
},
|
|
302076
|
+
installed_managed_files: [],
|
|
302008
302077
|
});
|
|
302078
|
+
this._newlyProvisionedAddresses = [];
|
|
302009
302079
|
}
|
|
302010
302080
|
async loadResources(tfOp) {
|
|
302011
302081
|
gh_provisioner_src_logger.info(`[gh-provisioner] running ${tfOp} on ${this.k8sId}`);
|
|
@@ -302016,9 +302086,22 @@ class EntityGHFeature extends base_Entity {
|
|
|
302016
302086
|
value: `${repoRef.cr.spec.org}/${repoRef.getDepName()}`,
|
|
302017
302087
|
});
|
|
302018
302088
|
try {
|
|
302019
|
-
|
|
302020
|
-
|
|
302021
|
-
|
|
302089
|
+
if (tfOp === 'import-with-reimport') {
|
|
302090
|
+
// Migration reimport path: only non-user-managed files go into config;
|
|
302091
|
+
// installed_managed_files is seeded from all userManaged:true addresses.
|
|
302092
|
+
// preApplyStateRm and keepUntrackedFiles are both skipped — the
|
|
302093
|
+
// destroy-state-only step inside runOnTerraform handles legacy state cleanup.
|
|
302094
|
+
await seedForMigrationReiimport(this);
|
|
302095
|
+
}
|
|
302096
|
+
else {
|
|
302097
|
+
const { newlyProvisionedAddresses, installedManagedFiles } = await provisionManagedFiles(this);
|
|
302098
|
+
this._newlyProvisionedAddresses = newlyProvisionedAddresses;
|
|
302099
|
+
if (tfOp === 'apply') {
|
|
302100
|
+
await this.preApplyStateRm(installedManagedFiles);
|
|
302101
|
+
}
|
|
302102
|
+
if (tfOp === 'destroy') {
|
|
302103
|
+
await this.keepUntrackedFiles(tfOp);
|
|
302104
|
+
}
|
|
302022
302105
|
}
|
|
302023
302106
|
gh_provisioner_src_logger.debug(`[gh-provisioner] ${this.k8sId} loaded its data`);
|
|
302024
302107
|
this.synthMessage('Synth finished');
|
|
@@ -302029,31 +302112,107 @@ class EntityGHFeature extends base_Entity {
|
|
|
302029
302112
|
throw `[gh-provisioner] ${this.k8sId} error loading resources: ${err}`;
|
|
302030
302113
|
}
|
|
302031
302114
|
}
|
|
302032
|
-
async postProvision(tfOp) {
|
|
302033
|
-
|
|
302034
|
-
|
|
302115
|
+
async postProvision(tfOp) {
|
|
302116
|
+
if (tfOp !== 'apply' || this._newlyProvisionedAddresses.length === 0) {
|
|
302117
|
+
return;
|
|
302118
|
+
}
|
|
302119
|
+
const addresses = this._newlyProvisionedAddresses.map((addr) => `github_repository_file.user_managed["${addr}"]`);
|
|
302120
|
+
gh_provisioner_src_logger.info(`[gh-provisioner] ${this.k8sId} post-apply state rm for newly provisioned user-managed files: [${addresses.join(', ')}]`);
|
|
302121
|
+
await runOnTerraform(this, 'custom-command', ['state', 'rm'].concat(addresses));
|
|
302122
|
+
}
|
|
302123
|
+
/**
|
|
302124
|
+
* Called by `runOnTerraform` during `import-with-reimport` after
|
|
302125
|
+
* `loadResources('import-with-reimport')` has already seeded `config.files`
|
|
302126
|
+
* with only non-user-managed files.
|
|
302127
|
+
*
|
|
302128
|
+
* Emits one import block per file:
|
|
302129
|
+
* to: github_repository_file.managed["<file>/<branch>"]
|
|
302130
|
+
* id: <repoName>:<file>:<branch>
|
|
302131
|
+
*
|
|
302132
|
+
* User-managed files are intentionally excluded (see ADR 0005).
|
|
302133
|
+
*/
|
|
302134
|
+
async loadAddressesToImport() {
|
|
302135
|
+
const repoRef = base_Entity.refResolver(this.cr.spec.repositoryTarget.ref);
|
|
302136
|
+
const repoName = repoRef.getDepName();
|
|
302137
|
+
for (const file of this.document.config.files) {
|
|
302138
|
+
this.patchImportData({
|
|
302139
|
+
op: PatchOperations.add,
|
|
302140
|
+
path: '/imports/-',
|
|
302141
|
+
value: {
|
|
302142
|
+
to: `github_repository_file.managed["${file.file}/${file.branch}"]`,
|
|
302143
|
+
id: `${repoName}:${file.file}:${file.branch}`,
|
|
302144
|
+
},
|
|
302145
|
+
});
|
|
302146
|
+
}
|
|
302147
|
+
}
|
|
302148
|
+
/**
|
|
302149
|
+
* Pre-apply state rm — runs inside loadResources before the main TF operation.
|
|
302150
|
+
*
|
|
302151
|
+
* Fetches the current TF state list, then removes any user-managed resource
|
|
302152
|
+
* addresses that are in installedManagedFiles AND are not currently
|
|
302153
|
+
* transitioning from userManaged:true to userManaged:false. This prevents
|
|
302154
|
+
* Terraform from planning a destroy for files that were dropped from the
|
|
302155
|
+
* feature definition or are still under user control from a previous apply.
|
|
302156
|
+
*/
|
|
302157
|
+
async preApplyStateRm(installedManagedFiles) {
|
|
302158
|
+
if (installedManagedFiles.length === 0)
|
|
302159
|
+
return;
|
|
302035
302160
|
try {
|
|
302036
|
-
|
|
302037
|
-
|
|
302038
|
-
|
|
302039
|
-
|
|
302040
|
-
|
|
302041
|
-
|
|
302042
|
-
|
|
302043
|
-
|
|
302044
|
-
|
|
302161
|
+
const stateListOutput = await runOnTerraform(this, 'custom-command', [
|
|
302162
|
+
'state',
|
|
302163
|
+
'list',
|
|
302164
|
+
]);
|
|
302165
|
+
const stateAddresses = parseStateList(stateListOutput);
|
|
302166
|
+
// Files that are transitioning from userManaged:true → false must NOT be
|
|
302167
|
+
// state-rm'd because Terraform needs them in state to manage them going forward.
|
|
302168
|
+
const transitioningToManaged = new Set((this.cr.spec.files ?? [])
|
|
302169
|
+
.filter((f) => !f.userManaged)
|
|
302170
|
+
.map((f) => `${f.path}/${f.targetBranch || this.cr.spec.repositoryTarget.branch}`));
|
|
302171
|
+
const addressesToRemove = stateAddresses.filter((addr) => {
|
|
302172
|
+
const match = addr.match(/^github_repository_file\.user_managed\["(.+)"\]$/);
|
|
302173
|
+
if (!match)
|
|
302174
|
+
return false;
|
|
302175
|
+
const fileAddress = match[1];
|
|
302176
|
+
return (installedManagedFiles.includes(fileAddress) &&
|
|
302177
|
+
!transitioningToManaged.has(fileAddress));
|
|
302045
302178
|
});
|
|
302046
|
-
|
|
302179
|
+
if (addressesToRemove.length > 0) {
|
|
302180
|
+
gh_provisioner_src_logger.info(`[gh-provisioner] ${this.k8sId} pre-apply state rm: [${addressesToRemove.join(', ')}]`);
|
|
302181
|
+
await runOnTerraform(this, 'custom-command', ['state', 'rm'].concat(addressesToRemove));
|
|
302182
|
+
}
|
|
302183
|
+
}
|
|
302184
|
+
catch (err) {
|
|
302185
|
+
throw new Error(`[gh-provisioner] ${this.k8sId} pre-apply state rm failed: ${err}`);
|
|
302186
|
+
}
|
|
302187
|
+
}
|
|
302188
|
+
/**
|
|
302189
|
+
* Destroy path — removes user-managed file resources from TF state before
|
|
302190
|
+
* the destroy operation so Terraform does not delete them from GitHub.
|
|
302191
|
+
*
|
|
302192
|
+
* Uses `terraform state list` to discover what is actually in state rather
|
|
302193
|
+
* than reading config.files, making this robust whether the entity was last
|
|
302194
|
+
* provisioned with old or new code.
|
|
302195
|
+
*/
|
|
302196
|
+
async keepUntrackedFiles(_tfOp) {
|
|
302197
|
+
try {
|
|
302198
|
+
gh_provisioner_src_logger.debug(`[gh-provisioner] ${this.k8sId} loaded untrack files ${this.k8sId}`);
|
|
302199
|
+
// Propagate session fields from parent if present
|
|
302200
|
+
if (this.parent) {
|
|
302201
|
+
this.sessionId = this.parent.sessionId;
|
|
302202
|
+
this.sessionProjectPath = this.parent.sessionProjectPath;
|
|
302203
|
+
this.__ghProvisionerSessionWorkspaceInitialized =
|
|
302204
|
+
this.parent.__ghProvisionerSessionWorkspaceInitialized;
|
|
302205
|
+
}
|
|
302206
|
+
const stateListOutput = await runOnTerraform(this, 'custom-command', [
|
|
302207
|
+
'state',
|
|
302208
|
+
'list',
|
|
302209
|
+
]);
|
|
302210
|
+
const stateAddresses = parseStateList(stateListOutput);
|
|
302211
|
+
const untrackedFiles = stateAddresses.filter((addr) => /^github_repository_file\.user_managed\[".+"\]$/.test(addr));
|
|
302212
|
+
gh_provisioner_src_logger.info(`[gh-provisioner] ${this.k8sId} keeping the following files [${untrackedFiles.join(', ')}]`);
|
|
302047
302213
|
if (untrackedFiles.length > 0) {
|
|
302048
|
-
// Propagate session fields from parent if present
|
|
302049
|
-
if (this.parent) {
|
|
302050
|
-
this.sessionId = this.parent.sessionId;
|
|
302051
|
-
this.sessionProjectPath = this.parent.sessionProjectPath;
|
|
302052
|
-
this.__ghProvisionerSessionWorkspaceInitialized =
|
|
302053
|
-
this.parent.__ghProvisionerSessionWorkspaceInitialized;
|
|
302054
|
-
}
|
|
302055
302214
|
const operationOutputs = await runOnTerraform(this, 'custom-command', ['state', 'rm'].concat(untrackedFiles));
|
|
302056
|
-
this.synthMessage(`\nkeeping files after feature uninstalled: \n ${
|
|
302215
|
+
this.synthMessage(`\nkeeping files after feature uninstalled: \n - ${untrackedFiles.join('\n - ')}`);
|
|
302057
302216
|
gh_provisioner_src_logger.debug(`[gh-provisioner] ${this.k8sId} state rm output ${operationOutputs}`);
|
|
302058
302217
|
}
|
|
302059
302218
|
}
|
|
@@ -302072,6 +302231,14 @@ class EntityGHFeature extends base_Entity {
|
|
|
302072
302231
|
return v;
|
|
302073
302232
|
}
|
|
302074
302233
|
}
|
|
302234
|
+
function parseStateList(output) {
|
|
302235
|
+
if (!output || typeof output !== 'string')
|
|
302236
|
+
return [];
|
|
302237
|
+
return output
|
|
302238
|
+
.split('\n')
|
|
302239
|
+
.map((line) => line.trim())
|
|
302240
|
+
.filter(Boolean);
|
|
302241
|
+
}
|
|
302075
302242
|
|
|
302076
302243
|
;// CONCATENATED MODULE: ../gh_provisioner/src/entities/ghmembership/helpers/index.ts
|
|
302077
302244
|
|
|
@@ -303364,16 +303531,16 @@ async function GHCheckRun(cmd, item) {
|
|
|
303364
303531
|
checkRun.mdOptionsDetails({
|
|
303365
303532
|
quotes: 'terraform',
|
|
303366
303533
|
});
|
|
303367
|
-
checkRun.update('Initiating', 'queued');
|
|
303534
|
+
void checkRun.update('Initiating', 'queued');
|
|
303368
303535
|
return {
|
|
303369
303536
|
fnData: (d) => {
|
|
303370
|
-
checkRun.update(d.toString(), 'in_progress');
|
|
303537
|
+
void checkRun.update(d.toString(), 'in_progress');
|
|
303371
303538
|
},
|
|
303372
303539
|
fnEnd: () => {
|
|
303373
|
-
checkRun.close('OK', true);
|
|
303540
|
+
void checkRun.close('OK', true);
|
|
303374
303541
|
},
|
|
303375
303542
|
fnOnError: (err) => {
|
|
303376
|
-
checkRun.close('KO', false);
|
|
303543
|
+
void checkRun.close('KO', false);
|
|
303377
303544
|
},
|
|
303378
303545
|
};
|
|
303379
303546
|
}
|
|
@@ -304517,7 +304684,7 @@ const crs_analyzerSubcommand = {
|
|
|
304517
304684
|
};
|
|
304518
304685
|
|
|
304519
304686
|
;// CONCATENATED MODULE: ./package.json
|
|
304520
|
-
const package_namespaceObject = JSON.parse('{"i8":"2.7.0-snapshot-
|
|
304687
|
+
const package_namespaceObject = JSON.parse('{"i8":"2.7.0-snapshot-19"}');
|
|
304521
304688
|
;// CONCATENATED MODULE: ../../package.json
|
|
304522
304689
|
const package_namespaceObject_1 = {"i8":"2.6.4"};
|
|
304523
304690
|
;// CONCATENATED MODULE: ./src/subcommands/index.ts
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export { provisionManagedFiles } from './managed_files';
|
|
1
|
+
export { provisionManagedFiles, seedForMigrationReiimport, } from './managed_files';
|
|
2
|
+
export type { ManagedFilesResult } from './managed_files';
|
|
@@ -1,2 +1,15 @@
|
|
|
1
1
|
import { EntityGHFeature } from '../';
|
|
2
|
-
export
|
|
2
|
+
export interface ManagedFilesResult {
|
|
3
|
+
newlyProvisionedAddresses: string[];
|
|
4
|
+
installedManagedFiles: string[];
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Migration reimport path for `import-with-reimport` operations.
|
|
8
|
+
*
|
|
9
|
+
* Populates `config.files` with ONLY non-user-managed files so the subsequent
|
|
10
|
+
* `loadAddressesToImport` can generate correct import blocks for them.
|
|
11
|
+
* Seeds `installed_managed_files` from ALL `userManaged: true` addresses in the
|
|
12
|
+
* current CR spec so the TFM input is ready for the next regular apply cycle.
|
|
13
|
+
*/
|
|
14
|
+
export declare function seedForMigrationReiimport(ghFeature: EntityGHFeature): Promise<void>;
|
|
15
|
+
export declare function provisionManagedFiles(ghFeature: EntityGHFeature): Promise<ManagedFilesResult>;
|
|
@@ -1,9 +1,39 @@
|
|
|
1
1
|
import { Entity } from '../base';
|
|
2
2
|
export declare class EntityGHFeature extends Entity {
|
|
3
|
+
_newlyProvisionedAddresses: string[];
|
|
3
4
|
constructor(artifact: any);
|
|
4
5
|
loadResources(tfOp: string): Promise<void>;
|
|
5
6
|
postProvision(tfOp: string): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Called by `runOnTerraform` during `import-with-reimport` after
|
|
9
|
+
* `loadResources('import-with-reimport')` has already seeded `config.files`
|
|
10
|
+
* with only non-user-managed files.
|
|
11
|
+
*
|
|
12
|
+
* Emits one import block per file:
|
|
13
|
+
* to: github_repository_file.managed["<file>/<branch>"]
|
|
14
|
+
* id: <repoName>:<file>:<branch>
|
|
15
|
+
*
|
|
16
|
+
* User-managed files are intentionally excluded (see ADR 0005).
|
|
17
|
+
*/
|
|
6
18
|
loadAddressesToImport(): Promise<void>;
|
|
7
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Pre-apply state rm — runs inside loadResources before the main TF operation.
|
|
21
|
+
*
|
|
22
|
+
* Fetches the current TF state list, then removes any user-managed resource
|
|
23
|
+
* addresses that are in installedManagedFiles AND are not currently
|
|
24
|
+
* transitioning from userManaged:true to userManaged:false. This prevents
|
|
25
|
+
* Terraform from planning a destroy for files that were dropped from the
|
|
26
|
+
* feature definition or are still under user control from a previous apply.
|
|
27
|
+
*/
|
|
28
|
+
preApplyStateRm(installedManagedFiles: string[]): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Destroy path — removes user-managed file resources from TF state before
|
|
31
|
+
* the destroy operation so Terraform does not delete them from GitHub.
|
|
32
|
+
*
|
|
33
|
+
* Uses `terraform state list` to discover what is actually in state rather
|
|
34
|
+
* than reading config.files, making this robust whether the entity was last
|
|
35
|
+
* provisioned with old or new code.
|
|
36
|
+
*/
|
|
37
|
+
keepUntrackedFiles(_tfOp: string): Promise<void>;
|
|
8
38
|
getFileContentFromProvider(org: string, url: string): Promise<string>;
|
|
9
39
|
}
|